WeakReference / AsyncTask template in android

I have a question regarding this simple common situation in android.

We have a main action, we call AsyncTask together with a link to mainactivity so that AsyncTask can update the views in MainActivity.

I am breaking the event into steps

  • MainActivity creates an AyncTask, passes its link to it.
  • AysncTask, starts its work, loading ten files, for example
  • The user has changed the orientation of the device. This leads to an orphan in AsyncTask
  • When AsyncTask shuts down and tries to access activity to update state, it crashes due to a null pointer.

The solution for the above is to save the WeakReference in AsyncTask, as recommended in 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 is, if my asynthesis downloads ten files, and after 5, activity restarts (due to a change in orientation), will my FileDownloadingTask be called again ?.

What will happen to the previous AsyncTask that was originally called?

Thank you and I apologize for the question.

+43
java android android-asynctask weak-references
Aug 18 '13 at 8:50
source share
3 answers

How does this resolve the situation?

WeakReference allows Activity to collect garbage, so you don't have a memory leak.

A null reference means that AsyncTask cannot blindly try to update a user interface that is no longer bound, which will throw exceptions (for example, the view is not bound to window manager). Of course, you should check for a null value to avoid NPE.

if my asynthesis loads ten files, and after completion of 5 the activity restarts (due to a change in orientation), will my FileDownloadingTask be called again?

It depends on your implementation, but probably yes - if you are not intentionally doing something to make reloading unnecessary, for example, caching the results somewhere.

What will happen to the previous AsyncTask that was originally called?

In earlier versions of Android, it started before completion, downloading all the files only for their dumping (or, possibly, caching them, depending on your implementation).

In the new Android, I suspiciously that AsyncTask dies along with the Activity that launched them, but my basis for the suspicion is only that the memory leak demonstration for RoboSpice (see below) does not actually flow on my JellyBean devices.

If I can offer some tips: AsyncTask not suitable for performing potentially lengthy tasks such as networking.

IntentService is the best (and yet relatively simple) approach if one working thread is acceptable to you. Use the (local) Service if you want to control the thread pool, and be careful not to 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, I am not an affiliate). The game store has a demo application called RoboSpice Motivations , which explains why you should use it, disassembling anything that might go wrong with AsyncTask - including the WeakReference workaround.

See also this topic: Is AsyncTask conceptually flawed or am I just missing something?

Update:

I created a github project with an example download using IntentService for another SO question ( How to fix android.os.NetworkOnMainThreadException? ), But it is also relevant here, I think. This has the added benefit that by returning the result via onActivityResult , a download that is in flight when you rotate the device will be delivered to a restarted Activity .

+30
Aug 19 '13 at 8:26
source share

The WeakReference class basically just forbids the JRE to increment the reference counter for this instance.

I will not go into Java memory management and answer your question directly: WeakReference addresses the situation by providing AsyncTask way to find out if its parent asset is retained.

Changing the orientation itself will not automatically restart AsyncTask . You must encode the desired behavior using well-known mechanisms ( onCreate / onDestroy , onSave/RestoreInstanceState ).

As for the original AsyncTask , I'm not 100% sure which of these options will happen:

  • Any Java stops the thread and provides AsyncTask , because the only object containing the link to it is destroyed (the original Activity )
  • Or some internal Java object maintains a reference to an AsyncTask object, blocking garbage collection, effectively leaving AsyncTask finished in the background

In any case, it would be good practice to interrupt / pause and restart / restart AsyncTask manually (or transfer it to a new Activity ) or use Service instead.

+6
Aug 18 '13 at 20:50
source share

How does this resolve the situation?

This is not true.

WeakReference to null when the garbage collector determines that the referent is poorly accessible. This does not happen when the action is paused and does not necessarily happen immediately when the action is destroyed, and the environment discards all references to it. If the GC is not running, it is possible that AsyncTask will AsyncTask while its WeakReference still contains a link to dead activity.

Not only that, but this approach does nothing to prevent AsyncTask from wasting CPU uselessly.

The best approach is to Activity maintain a strong reference to AsyncTask and cancel(...) in the appropriate method of a long break cycle. AsyncTask should monitor isCancelled() and stop working if it is no longer needed.

If you want AsyncTask withstand configuration changes (but not other forms of killing activity), you can place it in a saved fragment.

+1
Apr 24 '17 at 6:09
source share



All Articles