Unheilig
Unheilig

Reputation: 16302

AsyncTask questions

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 the AsyncTask (ATask) gets destroyed and when ATask 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 destroyed Activity? 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

Answers (2)

CodeWarrior
CodeWarrior

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

nzackoya
nzackoya

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

Related Questions