Android WeakReference on anonymous callback (listener)


WeakReference helps a lot for fixing memory leaks in Android applications, but also it can break your code. For example, using WeakReference on anonymous inner class is dangerous, because usually no other object holds a reference to it, and therefore, this anonymous inner class (object) can be garbage collected very fast.

Consider an example:

public class MainActivity extends AppCompatActivity {
    private View someView;
    ...

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

    private void someMethod() {
        ...
        new LongLiveObject(new LongLiveObject.Callback() {
            @Override
            public void onDone() {
                ...
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        someView.setVisibility(View.GONE);
                    }
                });
                ...
            }
        }).doSomething();
    }
}

public class LongLiveObject {
    public interface Callback {
        void onDone();
    }

    ...

    private final WeakReference<Callback> weakCallback; // don't do this!

    public LongLiveObject(Callback callback) {
        this.weakCallback = new WeakReference<>(callback);
    }

    ...

    public void doSomething() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ...
                // long running code here
                ...
                Callback callback = weakCallback.get();
                if (callback != null) {
                    callback.onDone();
                }
            }
        }).start();
    }
}

Android fixing memory leaks in legacy code


There are a lot of memory leaks in android applications that were written several years ago without using modern libraries. Fortunately, most of them can be easily fixed without additional dependencies.

Inner AsyncTask leak

public class MainActivity extends AppCompatActivity {
    private TextView textView;
    private View someOtherView;
    ...

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

    ...

    private void someMethod() {
        ...
        new MyAsyncTask().execute();
    }

    private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            ...
            some code
            ...
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            textView.setText("done");
            someOtherView.setVisibility(View.GONE);
        }
    }
}

There is a MainActivity memory leak here, because MyAsyncTask class has implicit reference to it, and therefore, MyAsyncTask may prevent MainActivity to be garbage collected (in case if it will outlive activity).
To fix this kind of memory leak, we need to declare MyAsyncTask class with a static keyword. It will help to remove implicit reference to MainActivity. Secondly, to deal with missing references in MyAsyncTask, we should use WeakReference on MainActivity to get them if activity exist:

Android new Throwable().printStackTrace()


Sometimes it’s very hard to navigate through code that you didn’t write. Especially if that code was written a long time ago, and has thousands of lines, and a complex architecture. „Find Usages” option in Android Studio may not help you, and understanding what is going on can be difficult and frustrating. It would be very nice to have a simple mechanism which can show you a stack trace at desired code location. Like while printing exceptions:


Fortunately, we can easily show stack trace at any code location by calling: