Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Activity's member scope and Asynctask

I initialize a member variable in my Activity class

private String test = new String("A");

then I use it to write to Log in a long time consuming loop in doInBackground() method of an anonymous AsyncTask launched from the Activity

new AsyncTask<Void, Void, Void>() {
   @Override
   protected void onPreExecute() {
   }

   @Override
   protected void onPostExecute(Void result) {
   }

   @Override
   protected Void doInBackground(Void... params) {

     for (int j = 10; j >= 0; j--) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.i("DOINBACKGROUND ", test);
     }

}.execute(); 

QUESTION: When I leave Activity while Asynctask is still executing, and after Activity's onDestroy() is executed, I see in the Log that the member variable is still alive and not destroyed. Can someone explain to me how is it possible?

BOUNTY QUESTION: the member variable is still alive because, even after onDestroy(), it isnt yet garbaged due to gc criteria and gc priority. This is ok.

But my doubt is if

  • the 'test' member variable (and the activity's context) will not garbaged until the referencing asynctask ended its stuff, thus asynctask can complete its doInBackground() always and surely without crashing (although with a temporary memory consumption)

or instead

  • the 'test' member variable will be garbaged sooner or later regardless asynctask is running, maybe resulting in an asysnctask's crash
like image 388
GPack Avatar asked Jun 24 '15 16:06

GPack


People also ask

What happens to AsyncTask if activity is destroyed?

If you start an AsyncTask inside an Activity and you rotate the device, the Activity will be destroyed and a new instance will be created. But the AsyncTask will not die. It will go on living until it completes.

What are the problems in AsyncTask?

In summary, the three most common issues with AsyncTask are: Memory leaks. Cancellation of background work. Computational cost.

How many times an instance of AsyncTask can be executed?

AsyncTask instances can only be used one time.

How can I use AsyncTask in different activities in android?

AsyncTask class is firstly executed using execute() method. In the first step AsyncTask is called onPreExecute() then onPreExecute() calls doInBackground() for background processes and then doInBackground() calls onPostExecute() method to update the UI.


2 Answers

Don't confuse garbage collection and the activity lifecycle.

An object can be garbage collected once all references traceable to it from GC root objects are gone.

onDestroy() is part of the activity lifecycle. Essentially the framework is done with the activity and is giving up any references it might have been holding to the activity and related resources.

When you instantiate an anonymous inner class, it gets an implicit reference to the parent object. To put it in another way, an anon inner class is always a non-static inner class. This parent reference is a reference to your Activity. You're then passing the async task object to an executor with a call to execute() and the executor holds the async task reference as long as it is needed, also preventing the referenced activity from being garbage collected.


Thus the asynctask in my snippet example will complete its doInBackground() always and surely without crashing due to NPE?

Yes. But do consider the following:

  • Make your inner classes static unless they specifically need to access the parent object. Since anon inner classes are always non-static, make them non-anonymous.

  • Mixing async operations in objects with separate lifecycle (such as activities or fragments) is fragile and it is better avoided. Problems include e.g. cancellation, results delivery to a gone object, and keeping GC-preventing references to expensive objects such as activities.

like image 176
laalto Avatar answered Oct 22 '22 09:10

laalto


First of all, onDestroy() happens just before destroying the activity and asks the activity manager to release all the resources tied to that activity. It means that all the activity's resources will be candidate for being removed by gc. However, it doesn't force the gc to remove the resources from the memory, they are just candidates. These candidate will be scored by the gc based on their size, age, recency, type and etc and whenever the system needs more space, it asks gc to remove candidates and it does it based on their scores. The candidate with a higher score is most likely to be deleted first.

This is noticeable when you see a crash out of nowhere, even after you quit from your application.

You might be able to see this crash if you create another activity and call System.gc() on it.

Cheers A.

like image 38
Amin Tavassolian Avatar answered Oct 22 '22 09:10

Amin Tavassolian