Skip to content

Instantly share code, notes, and snippets.

@belachkar
Last active August 17, 2020 02:58
Show Gist options
  • Save belachkar/d3dced62a0fe8b8552cc1c0fc403a605 to your computer and use it in GitHub Desktop.
Save belachkar/d3dced62a0fe8b8552cc1c0fc403a605 to your computer and use it in GitHub Desktop.

Android how to use static inner AsyncTask class

S1

To prevent leaks in memory, you can make the inner class static.

The problem with that, though, is that you no longer have access to the Activity's UI views or member variables.

You can pass in a reference to the Context but then you run the same risk of a memory leak. (Android can't garbage collect the Activity after it closes if the AsyncTask class has a strong reference to it.)

The solution is to make a weak reference to the Activity (or whatever Context you need).

public class MyActivity extends AppCompatActivity {

    int mSomeMemberVariable = 123;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // start the AsyncTask, passing the Activity context
        // in to a custom constructor 
        new MyTask(this).execute();
    }

    private static class MyTask extends AsyncTask<Void, Void, String> {

        private WeakReference<MyActivity> activityReference;

        // only retain a weak reference to the activity 
        MyTask(MyActivity context) {
            activityReference = new WeakReference<>(context);
        }

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

            // do some long running task...

            return "task finished";
        }

        @Override
        protected void onPostExecute(String result) {

            // get a reference to the activity if it is still there
            MyActivity activity = activityReference.get();
            if (activity == null || activity.isFinishing()) return;

            // modify the activity's UI
            TextView textView = activity.findViewById(R.id.textview);
            textView.setText(result);

            // access Activity member variables
            activity.mSomeMemberVariable = 321;
        }
    }
}

S2

This AsyncTask class should be static or leaks might occur because:

  • When Activity is destroyed, AsyncTask (both static or non-static) still running
  • If inner class is non-static (AsyncTask) class, it will have reference to the outer class (Activity).
  • If a object has no references point to it, Garbage Collected will release it. If a object is unused and Garbage Collected can not release it => leak memory.

=> If AsyncTask is non-static, Activity won't release event it is destroyed => leak

Solution for update UI after make AsyncTask as static class without leak

  1. Use WeakReference.
  2. Send and remove Activity reference to (from) AsyncTask.
public class NoLeakAsyncTaskActivity extends AppCompatActivity {
    private ExampleAsyncTask asyncTask;

    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        ...

        // START AsyncTask
        asyncTask = new ExampleAsyncTask();
        asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
            @Override
            public void onExampleAsyncTaskFinished(Integer value) {
                // update UI in Activity here
            }
        });
        asyncTask.execute();
    }

    @Override
    protected void onDestroy() {
        asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
        super.onDestroy();
    }

    static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
        private ExampleAsyncTaskListener listener;

        @Override
        protected Integer doInBackground(Void... voids) {
            ...
            return null;
        }

        @Override
        protected void onPostExecute(Integer value) {
            super.onPostExecute(value);
            if (listener != null) {
                listener.onExampleAsyncTaskFinished(value);
            }
        }

        public void setListener(ExampleAsyncTaskListener listener) {
            this.listener = listener;
        }

        public interface ExampleAsyncTaskListener {
            void onExampleAsyncTaskFinished(Integer value);
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment