Contexts, AsyncTask and rotation changes - android

Is it a good practice to use getApplicationContext() working with AsyncTask in order to do not have to attach and detach the Activity to avoid memory leaks when rotation changes occur and the Activity is destroyed? I thing it should be correct, as I actually need a Context that depends on the hole application, not the Activity itself.
And what is more, in those cases in which is better to use the Activity as context (because you need access to the Activity showing)... Instead of detaching it (assigning to null) when it is destroyed and then assign the new instance in onCreate(), could be just avoid detaching? So, just reasigning the new instance, this way, we could avoid problems of NullPointerException because there would always be a context to use!

This post and its answers are a good explanation of what to do. This post and its answers explain some good theory behind the AsyncTask and Context issue.

From my own experience I can say that in most cases it is better to use Activity as your Context, than getApplicationContext() when dealing with AsyncTask. This is because most of times you will need to access members from your Activity and you will only be allowed to do so if you have a reference to the Activity in your AsyncTask.
To answer my question about avoiding detach(), let me say that in this case you can avoid it or just do it without any problems, as #CommonsWare states in his answer. So, from what he says we are sure that we will not get a NullPointerException while the Activity is null during a rotation change:
onProgressUpdate() and onPostExecute() are suspended between the start of onRetainNonConfigurationInstance() and the end of the subsequent onCreate()
If I am not wrong, the main difference between not detaching explicitly and just re-attaching the new one in the onCreate() of the newly created Activity is that you free the old Activity instance some milliseconds later when just reattaching. But the final behavior is the same in both cases!
Hope this helps someone else! :)

Related

What to do when activity is destroyed but I must continue executing code in fragment?

I have a pretty odd problem here. In a fragment, I do a process and when the process finishes I show an advert that callsback to the fragment when user clicks/dismisses the ad. The problem is that in some devices when the ad calls back to the handler (that is in the running fragment) the activity containing the fragment has been destroyed, but I need to do some more work through a runnable. So, in this case the runnable throws a NullPointerException int is run method when executed.
I could just check if the activity is still alive and run just the runnable when it is, but in the cases it is not alive I still need to continue to do the part of the job that needs to be done after the ad.
How do you handle this kind of situations? I have been thinking about the problem during some hours without finding a solution to this.
Thanks in advance.
You can use AsyncTask in this case .
AsyncTask processes are not automatically killed by the OS. AsyncTask processes run in the background and is responsible for finishing it's own job in any case. You can cancel your AsycnTask by calling cancel(true) method. This will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object) method is called instead of onPostExecute() after doInBackground() returns.
Hope it helps..
mmm the way this is asked I am not sure what you are asking, perhaps some text connectors might work, I am not sure if this is a quite basic question about state changes or a very complex one.
from what I understood:
wouldn't this be the same problem as when you flip screen? make a Bundle of the data that is restored through activity changes. This way if your activity has been Destroyed you restore it
fragments have a feature that you can use to keep instance alive across a configuration change: retainInstance
setRetainInstance(true) // false by default
Parcelable like Serializable, is an API for saving an object out to a stream of bytes. Objects may elect to implement the Parcelable interface if they are what we will call "stashable" here. Objects are stashed in Java by putting them in a Bundle, or by marking them Serializable so they can be serialized, or by implementing the Parcelable interface. Whichever way you do it, the same idea applies: you should not be using any of these tools unless your object is stashable
---or---
turn that "advert" of yours into an Alert, which wont mess with the Activity.
---or---
run the response on a different thread?

Down sides of Async Task If Any

I know you are using it quite well with your Non-UI codes in AsnycTask but I am just wondering if there is any kind of problem while using AsyntTask? I am not having any code which produce the problem. But I am just curious to know Any bad experience if you have with AsnycTask and would like to share it.
Memory Leak :
Even though activity is destroyed, AsyncTask holds the Activity's reference since it has to update UI with the callback methods.
cancelling AsyncTask :
cancelling AsyncTask using cancel() API will not make sure that task will stop immediately.
Data lose :
When screen orientation is done. Activity is destroyed and recreated, hence AsysncTask will hold invalid reference of activity and will trouble in updating UI.
Concurrent AsyncTasks: Open Asynctask.java go to line number 199, it shows you can create only 128 concurrent tasks
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);
Rotation: When Activity is restarted, your AsyncTask’s reference to the Activity is no longer valid, so onPostExecute() will have no effect.
Cancelling AsyncTasks: If you AsyncTask.cancel() it does not cancel your AsyncTask. It’s up to you to check whether the AsyncTask has been canceled or not.
Lifecycle: AsyncTask is not linked with Activity or Fragment, so you have to manage the cancellation of AsyncTask.
There are some workarounds to solve above issues for more details have a look at The Hidden Pitfalls of AsyncTask
I just want to share the information that if you are using Asynctask, it will keep on doing its work even of the activity does not exist.
So in case you have asynctask which starts in onCreate() of the activity, and you rotate the device. At each rotation, a new activity is created with a new instance of Asysntask. So many requests will be send over the network for same task.In this way, a lot of memory will be consumed which effects the app performance resulting in crashing it. So to deal with it Loaders(Asynctask Loaders) are used.
For more info check the video:
Loaders

What is the lifecycle of Loaders?

Background
I'm working on making an app better by supporting its landscape mode. One thing that I use a lot is Loaders, or more specifically AsyncTaskLoaders .
Using Loaders allow you to keep doing a background task even if the activity is being re-created due to orientation changes, as opposed to AsyncTask.
The question
I'd like to ask about the lifecycle of Loaders:
When do they get GC-ed ? Do I have to keep track of them, and if one has a bitmap inside, should I abandon it as soon as possible? Do they perhaps get GC-ed only after the activity is really destroyed (and not because of configuration changes) ?
I've noticed they have states of being stopped. Does this somehow allow me to pause them?
If #2 is true, How would I implement a loader that can be paused on some points of itself?
Can fragments also have Loaders? As I've noticed, it's only for activities.
if #4 is false, what is the recommended way to use loaders in the design pattern of navigation-drawer that replaces fragments in the container?
Can AsyncTaskLoader be interrupted like AsyncTask (or threads)? I've looked at its code and at the API, but I can't find it. I've also tried to find a workaround, but I didn't succeed.
If #6 is false, is there an alternative? For example, if I know that the loader doesn't need to load something, I could just stop it right away. One way I can think of is to set a flag (maybe AtomicBoolean, just in case) that will tell it to stop, and check this value sometimes within. Problem is that I will need to add it even inside functions that it uses, while an easier way would be to call "Thread.sleep(0)" or something like that.
Is there somewhere an explanation of the lifecycle of Loaders?
Do AsyncTaskLoaders work together, at the same time, or are they like the default, current behavior of AsyncTask, which runs only on a single thread ?
1.When do they get GC-ed ? Do I have to keep track of them, and if one has a bitmap inside, should I abandon it as soon as possible? Do they perhaps get GC-ed only after the activity is really destroyed (and not because of configuration changes) ?
Since the loader lifecycle is tied to the activity/fragment lifecycle, it is safe to assume that the garbage collection pretty much takes place at the same time. Take a look at #8 for the lifecycle of loaders. Might give you some ideas.
2.I've noticed they have states of being stopped. Does this somehow allow me to pause them?
No, as far as i know loaders do not have a onPause() per say.
3.If #2 is true, How would I implement a loader that can be paused on some points of itself?
I really have no answer to this one. Would like to know a solution to this myself.
4.Can fragments also have Loaders? As I've noticed, it's only for activities.
Of course fragments can have loaders. Just initialize the loaderManager in the onActivityCreated() method
5.if #4 is false, what is the recommended way to use loaders in the design pattern of navigation-drawer that replaces fragments in the container?
4 is true. So this question is irrelevant i guess.
6.Can AsyncTaskLoader be interrupted like AsyncTask (or threads)? I've looked at its code and at the API, but I can't find it. I've also tried to find a workaround, but I didn't succeed.
I am not sure what do you mean interrupting the loaders. But if you mean having something similar to a isCancelled() method, then there is a method called cancelLoad() on the AsyncTaskLoader. The complete flow is like cancelLoad()->cancel()->onCancelled() i think.
7.If #6 is false, is there an alternative? For example, if I know that the loader doesn't need to load something, I could just stop it right away. One way I can think of is to set a flag (maybe AtomicBoolean, just in case) that will tell it to stop, and check this value sometimes within. Problem is that I will need to add it even inside functions that it uses, while an easier way would be to call "Thread.sleep(0)" or something like that.
Irrelevant again?
9.Do AsyncTaskLoaders work together, at the same time, or are they like the default, current behavior of AsyncTask, which runs only on a single thread ?
Runs on a single thread.
8.Is there somewhere an explanation of the lifecycle of Loaders?
To my best of knowledge:
When activity/fragment is created the loader starts -> onStartLoading()
When activity becomes invisible or the fragment is detached the loader stops -> onStopLoading()
No callback when either the activity or the fragment is recreated. The LoaderManager stores the results in a local cache.
When activity/fragment is destroyed -> restartLoader() or destroyLoader() is called and the loader resets.
I hope this helps. I might be a bit off on some of the answers. I am constantly learning new things myself.
Cheers.

When can getActvity() in a retained, uncancelable DialogFragment be null?

If I have a DialogFragment that is retained and uncancelable, in what situations can getActivity() return null?
As far as I understand, the only ways an Activity can be destroyed are:
Via the back button - Which can't happen since my dialog is uncancelable
Via a rotate - This (I think) won't matter since my dialog is retained and the Activity will be re-attached (due to activity recreation in one main thread message) before any of my main thread callbacks are run.
The question I have is, am I missing a case? Or are my assumptions incorrect?
Not exactly an answer to your question, but I had a getActivity() to return null when used a Handler in a DialogFragment. Even if Handler had a link to DialogFragment instance it still had getActivity() as null in handleMessage() method. Would be glad to hear why does it happen.
P.S. Even more strange, what the first time this DialogFragment is created everything is fine. When we create a new instance of this DialogFragment he getActivity() in Handler starts to return null.
I suspect, that while we create a new DialogFragment, the Handler inside somehow still attached to the old one (which already is detached and doesn't have activity)
Must admit, that my Handler is not static as recommended.
P.P.S I use compat lib for fragments
Ok. After giving it some thought I think I understood my error. The handler from the first DialogFragment was registered in my service and was never unregistered. So when the message comes it goes into this handler as well. I believe it can cause a memory leak if not already :D

Should I null references to Activity Context, when my Activity finishes?

Is it a good practice to null references to Activity Context, when my Activity finishes? I have 3 AsyncTask's, each of them can be running in several instances simultaneously. The update the UI in onPostExecute(). Nulling all Activity Context references in onDestroy() would be quite difficult and make the code messy. What is the best thing to do?
Check WeakAsyncTask for an example from Google of an asynctask that doesn't keep references alive beyond the activity lifecycle, and BetterAsyncTask from DroidFu for an example of a way to wire AsyncTasks so they can reconnect to new activity instances (after a rotation, for example); usage example is here.
There's probably not too much harm in keeping the references to Activity around for a short operation (e.g. a single small web request or small file write), but if there's the possibility for the tasks to pile up, it could cause a problem. For example, if your app reads a 200KB XML file from a server on creation, which let's say can takes 1 minute or more over EDGE, a quick flip of the phone open/closed 3 or 4 times could lead to 4 retained Activity instances -- you can run out of memory pretty quickly in this situation, not to mention the duplicated work.
For any really long-running processes, though, you should definitely consider an IntentService instead of an AsyncTask. They're designed for longer-running processes that aren't really tied to a specific activity - like how you can send an MMS and leave the activity to go do other things, and you get a nice happy toast informing you of the completion of the task whenever it finishes.
Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself). Try using the context-application instead of a context-activity. Nulling the references is not needed when you do not need the opposite because of the memory troubles.
If the tasks will be eligible for garbage collection themselves shortly after your Activity finishes, I see no problem in keeping the references around.
If the tasks do outlive the activity for a significant amount of time, you should set all references to the Activity Context to null. See also the article Avoiding Memory Leaks.
Either way, it is good practice to use the Application Context (getApplicationContext()) instead of the Activity Context whenever you can. In this case you can't do this, because you need to post UI messages; I'm just mentioning it for completeness.
You can hold context reference using Weak reference. http://developer.android.com/reference/java/lang/ref/WeakReference.html
Weak referenced objects can be GC'd. You should just do check if you context reference is still valid every time you use it.

Categories

Resources