Leaking Inner Class

Context

Implementation

Affects

Memory Efficiency

Problem

Non-static inner classes holds a reference to the outer class. This could lead to a memory leak.

Here are two examples: One inner class and one anonymous inner class.

public class SampleActivity extends Activity {

    private final Handler mLeakyHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // ...
        }
    }

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

        // Post a message and delay its execution for 10 minutes.
        mLeakyHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                // do anything
            }
        }, 60 * 10 * 1000);

        // Go back to the previous Activity.
        finish();
    }
}

Refactorings

Introduce Static Class

Resolves

Memory Efficiency

Affects

Solution

Declare a static instance of the class:

/**
 * Instances of anonymous classes do not hold an implicit
 * reference to their outer class when they are "static".
 */
private static final Runnable sRunnable = new Runnable() {
  @Override
  public void run() {
      ...
  }
}

Links

Introduce Weak Reference

Resolves

Memory Efficiency

Affects

Solution

Use a WeakReference. Objects hold by WeakReferences will still be garbage collected.

public class SampleActivity extends Activity {
    private static class MyHandler extends Handler {
        private final WeakReference<SampleActivity> mActivity;
        public MyHandler(SampleActivity activity) {
            mActivity = new WeakReference<SampleActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            SampleActivity activity = mActivity.get();
            if (activity != null) {
                // ...
            }
        }
    }
    private final MyHandler mHandler = new MyHandler(this);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Post a message and delay its execution for 10 minutes.
        mHandler.postDelayed(... , 600000);
        // Go back to the previous Activity.
        finish();
    }
}

Links

Related