I have a question regarding this simple frequently occurring situation in android .
We have a main activity , we invoke an AsyncTask alongwith the reference of the mainactivity , so that that the AsyncTask can update the views on the MainActivity.
I will break down the event into steps
The solution for the above is to keep a WeakReference in the AsyncTask as recommended by the book "Pro Android 4"
WeakReference<Activity> weakActivity;
in method onPostExecute
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
How does this resolve the situation ?
My question it , if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.
What would happen to the previous AsyncTask that was initially invoked ?
Thank you , and I apologize for the length of the question .
Android AsyncTask is an abstract class provided by Android which gives us the liberty to perform heavy tasks in the background and keep the UI thread light thus making the application more responsive. Android application runs on a single thread when launched.
In summary, the three most common issues with AsyncTask are: Memory leaks. Cancellation of background work. Computational cost.
AsyncTask is used to perform time talking operations in android, but it's marked as deprecated from android 11.
WeakReference: a weak reference is a reference not strong enough to keep the object in memory. If we try to determine if the object is strongly referenced and it happened to be through WeakReferences, the object will be garbage-collected.
How does this resolve the situation ?
The WeakReference
allows the Activity
to be garbage collected, so you don't have a memory leak.
A null reference means that the AsyncTask
cannot blindly try to update a user-interface that is no longer attached, which would throw exceptions (e.g. view not attached to window manager). Of course you have to check for null to avoid NPE.
if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.
Depends on your implementation, but probably yes - if you don't deliberately do something to make a repeat download unnecessary, such as caching the results somewhere.
What would happen to the previous
AsyncTask
that was initially invoked ?
In earlier versions of Android it would run to completion, downloading all of the files only to throw them away (or perhaps cache them, depending on your implementation).
In newer Android's I am suspicious that AsyncTask
's are being killed along with the Activity
that started them, but my basis for suspicion is only that the memory-leak demo's for RoboSpice (see below) do not actually leak on my JellyBean devices.
If I may offer some advice: AsyncTask
is not suitable for performing potentially long running tasks such as networking.
IntentService
is a better (and still relatively simple) approach, if a single worker thread is acceptable to you. Use a (local) Service
if you want control over the thread-pool - and be careful not to do work on the main thread!
RoboSpice seems good if you are looking for a way to reliably perform networking in the background (disclaimer: I have not tried it; I am not affiliated). There is a RoboSpice Motivations demo app in the play store which explains why you should use it by demo-ing all the things that can go wrong with AsyncTask
- including the WeakReference workaround.
See also this thread: Is AsyncTask really conceptually flawed or am I just missing something?
Update:
I created a github project with an example of downloading using IntentService
for another SO question (How to fix android.os.NetworkOnMainThreadException?), but it is also relevant here, I think. It has the added advantage that, by returning the result via onActivityResult
, a download that is in flight when you rotate the device will deliver to the restarted Activity
.
The WeakReference
class basically just prevents the JRE to increase the reference counter for the given instance.
I won't go into Java's memory management and answer your question directly: The WeakReference
resolves the situation by providing the AsyncTask
a way to learn if its parent activity is still valid.
The orientation change itself will not automatically restart the AsyncTask
. You have to code the desired behavior with the known mechanisms (onCreate
/onDestroy
, onSave/RestoreInstanceState
).
Concerning the original AsyncTask
, I'm not 100 % sure which of these options will happen:
AsyncTask
, because the only object holding a reference to it (the original Activity
) is destroyedAsyncTask
object, blocking its garbage collection, effectively leaving the AsyncTask
to finish in the backgroundEither way, it would be good practice to abort/pause and restart/resume the AsyncTask
manually (or handing it over to the new Activity
), or use a Service
instead.
How does this resolve the situation ?
It doesn't.
The referent of a WeakReference
is set to null
when the garbage collector determines that the referent is weakly reachable. This does not happen when an activity is paused, and does not necessarily happen immediately when the activity is destroyed and the framework discards all references to it. If the GC has not run, it is entirely possible for the AsyncTask
to complete while its WeakReference
still contains a reference to a dead activity.
Not only that, but this approach does nothing to prevent the AsyncTask
from uselessly consuming CPU.
A better approach is to have the Activity
maintain a strong reference to the AsyncTask
and cancel(...)
it in the appropriate teardown lifecycle method. The AsyncTask
should monitor isCancelled()
and stop working if it is no longer needed.
If you want an AsyncTask
to survive across configuration changes (but not other forms of activity destruction) you can host it in a retained fragment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With