Reputation: 16302
I was reading things about AsyncTask
. It was understandable to me, but immediately two concerns came up to my mind:
Let say I have a class and an interface:
public MyInterface<T>
{
void done(T result);
}
public MyActivity extends Activity implements MyInterface<String>
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
R.getViewByID(R.....);
//...
beginTask(urls);
}
private void beginTask(URL[] urls)
{
ATask task = new ATask(this);
task.execute(urls);
}
@Override
void done()
{
System.out.println("done!");
}
}
And the AsyncTask
class:
public ATask extends AsyncTask<URL, Void, String>
{
MyInterface<String> handler = null;
private StringBuilder fetchedResult = new StringBuilder();
ATask(MyInterface<T> handler)
{
this.handler = handler;
}
@Override
protected String doInBackGround(URL urls...)
{
URL url = urls[0];
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url.toString());
ResponseHandler<String> handler = new BasicResponseHandler<String>();
String result = null;
try
{
result = client.execute(request, handler);
fetchResult.append(result);
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClientProtocolException e)
{
e.printStackTrace();
}
finally
{
client.getConnectionManager().shutdown();
}
return fetchResult.toString();
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
}
@Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
handler.done(result);
}
}
All is well. But the concerns that came to me were:
1.)
What if for some reasons the
Activity
(MyActivity
) that calls theAsyncTask
(ATask
) gets destroyed and whenATask
is finished and then calls done(); in the destroyed Activity? How could we prevent this from happening or is there a way to re-create the destroyedActivity
? What would be the best practice here?2.)
Another scenario: What if the background task takes a long time (intended, even though the App is no longer in view) in
doInBackground
? Would it then keep holding onto a reference of this Activity (MyActivity) for as long when the Activity (MyActivity) should be destroyed for memory's sake (i.e., when onStop() needs to be called)?
Upvotes: 1
Views: 166
Reputation: 5176
1.) As per the documentation :
onStop()
-> Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one.
ondestroy()
-> The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space
So you need to decide when do you want to call your task.cancel()
, it may depend on your business logic.
2.) As per the documentation AsyncTask
should be used for operations running only for a very few seconds. Whenever an AsyncTask
/Thread
is running and your activity gets destroyed then memory is leaked because they still hold the reference of your activity. To avoid any leak declare the AsyncTask
/Thread
as a private static inner class and in onDestroy()
close your thread by t.close
and in case of AsyncTask
set your activity to null
mActivity = null
so in both the cases your activity is now eligible for garbage collection.
Upvotes: 0
Reputation: 356
In both cases you have to override application onDestroy or activity onStop methods and call task.cancel(). So you need to keep reference to your task object.
Upvotes: 1