I am working on an app in which i have two Fragments hosted in one Activity. The acitivity layout has a bottom bar which has buttons that switch the two fragments.
In those fragments there are Threads that do some internet work and then update their layout.
Hieararchy:
Activity
Fragment 1
Thread 1
Fragment 2
Thread 2
The problem
The problem is that when, say Thread 1 starts doing some work, the user clicks the button to switch to Fragment 2, the Thread continues to run in the background, and when it is done with it's network task and tries to update the view (in the now not visible Fragment 1), the app crashes because getActivity() or getContext() now returns null.
EDIT: The thread uses getActivity() and getContext() a lot, not only for updating layout, but also for saving SharedPreferences, etc. I can add an inspection (if(!stopped) for example) to every line that uses Context, but i thought there is a better way than wrapping every step in an if condition.
So how do I kill either the Thread or Fragment completely? I don't need the background work running when the fragments are switched, I only need it to run when the fragment is visible.
I have tried both Thread.interrupt() and removing the fragment (instead of replacing) using getSupportFragmentManager.remove(Fragment fragment). Did not work.
Thanks in advance :)
You may check in your thread whether getActivity() is null and in this case do not perform UI update. A better aprach would be to stop your download once a user switches to another fragment - how to do it depends on what HTTP client you are using. With HttpURLConnection it should suffice to call disconnect().
Instead of using Thread consider using AsyncTask which has support for being cancelled. For examples search SO, here is one: Ideal way to cancel an executing AsyncTask.
Related
I have an Activity which can open 2 different Fragments by 2 different Buttons. By the default that Activity when it creates, it is opening a Fragment, we call it "The Main Fragment".
The first Fragment to which we are going over by the first Button we meet zero problems with the Rotation, but the second one after the rotation disappears and the screen shows the Main Fragment's content. When I tried to rotate the screen back, I see the Main Fragment's content again. But why it is so, if I didn't write any code, which must return me to the Main Fragment without clicking a button.
What assumptions do you have?
Why this is happening ?
Default Behavior, Actiivty is getting recreated on orientation change so your fragment are.
Explanation
You need to understand Activity Life Cycle to understand why this is happening.
First, “rotating the screen” is not the actual scenario we are talking about today. Because any configuration change will cause Android to restart your Activity. A configuration change might be the device rotating (because now we have a different screen layout to draw upon), or it could be a language switch (because we need to re-write all those strings, which may need more room now OR it could be the scary RTL switch!), or even keyboard availability.
By reloading your app, what the system is actually doing is calling onDestroy() and then immediately calling onCreate(). This way, your Activity is as fresh as possible, with all of the right creation data (even though the user has been with you the entire time).
Now you have following option -
Either Fix Orientation for your app from AndroidManifest.xml
But oviously that is not a very good experience for user.
Save activityState with onSaveInstanceState()
This method will be called before onDestroy(). And, when your Activity is created, there’s a matching step onRestoreInstanceState(), which will also be called automatically. All of these automatic steps mean that you can let the system worry about saving and loading your data, because you planned ahead and mapped out what was important. (Or, you can skip onRestoreInstanceState() and load your saved state from the Bundle that comes with onCreate().
In you integrate Fragment in activity, because activity is getting destroy() so your fragment will also destroy() and will be recreated.
Please take a good read on Handling Configuration Change and this.
Once you understood the concepts things will start falling into your but it will only happen if you will complete your learning curve.
Happy Coding !
That is because onCreate is being called every time the screen is rotated. Probably you are displaying The Main Fragment from your onCreate method. You will face the same issue if you put your fragment display logic in onResume because just after onCreate, onResume is called.
Solution: store the fragment on top in shared preferences that way you know what to display every time onCreate is being called.
I am trying to make an App which is going to display Some Images and Videos. So I am planning to add a splash screen of around 2seconds. After 2 seconds the user will be taken to the Main Screen of the App.
I want to start the loading of the Images, Video when then user is at the splash screen itself so that the user should wait for the least time when he is at the Main Screen.
So the loading will be started at the Splash Screen and then after two second the user will be taken to main screen irrespective of the completion of the loading.
Now since this involves two activities should I use a Async task or should I Use a service with an Async Task(For the callback of completion of code) within it?
Which one would be better. Also in Android 8.0 are there any restriction in using Services?
I think using a Async Task between two screens may cause Memory leak if not coded properly.
Any help would be really grateful.
EDIT: My app is having one more feature hence cannot make the user wait in the Splash Screen till the loading is over.
It is not very good to use AsyncTask for sharing results between 2 activities, because AsyncTack created in Splash activity will be destoyed (stopped) when switched to Main activity. Better to use service in this case and Main screen will subscribe for result.
So basically you want to start the download in the splash screen and continue the download in the activity that follows. In this way, you still have to implement a loading animation. In your case, I would recommend finishing your splash screen, as soon as everything is downloaded. In that way, you don't have to download anything anymore inside the app's lifecycle.
AsyncTasks continue to run even after switching to a new activity. You can try the following flow:
1. Splash screen
2. Trigger Async Task
3. Main Activity
4. Show Images/Videos
The only catch is, you will not be able to fix a time for #2 to complete to be able to start #4. This is the nature of AsyncTasks. You can workaround by using the OnPostExecute within AsyncTask.
Example: OnPostExecute call another method that will enable a button. Users can click on the button to view Images/Videos. But then, this might not be a good user experience to see some button suddenly getting enabled.
In that case I would rather create some Singleton with own Handler (that works in separate Thread), that will be started at Splash screen. After Main screen will start, it should ask that Singleton about respective data or should sign himself for receiving that data.
I have an navigation drawer Activity in which I have made 3 fragments using ViewPager. Each of the fragment has an edit Text, Image button and RecyclerView. The RecyclerView is getting data from a local SQLite database.
On opening the app, I get a Log trace that application skipped XX frames.
(Usually 30-50 frames). Is it normal ? If not, then what should I do? Can fragments be made using background thread like AsyncTask? Or should I populate RecyclerView in background thread?
Is it normal?
Nope. Check out Choreographer (start at line 619) if you are eager to find out what's happening behind the scenes.
what should I do? Can fragments be made using background thread like AsyncTask?
You can't do anything with Views on a background Thread since that would cause a CalledFromWrongThreadException, but what you definitely can and should do is moving all performance-heavy operations like DB read/write to worker Threads. Check out the AsyncTask and AsyncTaskLoader chapter from "Android Developer Fundamentals Course", it will give you a good start on background processing.
Also note that the LoaderManager from the support library is not deprecated.
So this is a tuff one. I have a activity that calls a class that call a http downloader which is the async task. What I want to do is have a please wait loading screen notification for the user while the activity is getting all the data from the web. I don't have a clue on how to get the loading screen to be called. Usually you would have it in the async task but my async task does not have a view. How to best go about doing this?
Thank you for any help.
My http client does have a doInBackground() so should I put the on preExecute and postExecute there? But then how would my main method which is twice removed know when its down and when its not.
What is happening is that when a button is clicked it starts the activity and starts to process all the methods, but it linger on the first activity until everything is done loading. I don't want that I want the progress dialog. It just won't show. Any thoughts on this?
NEW UPDATES
Ok so now I got this set up a bit better so now at least the progress dialog now shows up. the problem is the Async task does not stop running.
You should use an AsyncTask. It doesn't have to have a view, it's just a background process just like a thread.
Refer to this on how to use an AsyncTask properly with a ProgressDialog.
Do your methods in the doInBackground() method of the AsyncTask.
I have a ListFragment which depends on the hosting Activity to properly initialize. On first run, it loads up fine. Once I change the orientation, my app crashes. From the stack trace I can see it isn't me trying to add the Fragment prematurely, rather Android is trying to restore the Fragment.
I have setRetainInstance(false) set in the onStart method but can't find any method to disable the restoring of the Fragment once the orientation changes. Any ideas? Do I need to remove the Fragment prior to my app being destroyed?
Edit: I ended up delaying initializing the list until the Activity is ready. Android conveniently shows a 'loading' message until the adapter is set.
I ended up delaying initializing the list until the Activity is ready. Android conveniently shows a 'loading' message until the adapter is set.
I have a ListFragment which depends on the hosting Activity to properly initialize.
That may be your difficulty right there.
From the stack trace I can see it isn't me trying to add the Fragment prematurely, rather Android is trying to restore the Fragment.
Correct.
Any ideas?
I would focus on handling configuration changes properly. Between onSaveInstanceState() in the fragment and the combination of onRetainNonConfigurationInstance(), getLastNonConfigurationInstance() (both on Activity) and onAttach() (on your Fragment), you should be able to pass whatever stuff is in the old fragment to the new one without crashing. For configuration changes, do not rely upon "the hosting Activity to properly initialize".