http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

How to Leak a Context: Handlers & Inner Classes

Consider the following code:

?
1 2 3 4 5 6 7 8 9 public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } }

While not readily obvious, this code can cause cause a massive memory leak. Android Lint will give the following warning:"In Android, Handler classes should be static or leaks might occur."But where exactly is the leak and how might it happen? Let's determine the source of the problem by first documenting what we know:

  1. When an Android application first starts, the framework creates aLooperobject for the application's main thread. ALooperimplements a simple message queue, processingMessageobjects in a loop one after another. All major application framework events (such as Activity lifecycle method calls, button clicks, etc.) are contained insideMessageobjects, which are added to theLooper's message queue and are processed one-by-one. The main thread'sLooperexists throughout the application's lifecycle.

  2. When aHandleris instantiated on the main thread, it is associated with theLooper's message queue. Messages posted to the message queue will hold a reference to theHandlerso that the framework can callHandler#handleMessage(Message)when theLoopereventually processes the message.

  3. In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.

So where exactly is the memory leak? It's very subtle, but consider the following code as an example:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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() { } }, 60 * 10 * 1000 ); // Go back to the previous Activity. finish(); } }

When the activity is finished, the delayed message will continue to live in the main thread's message queue for 10 minutes before it is processed. The message holds a reference to the activity'sHandler, and theHandlerholds an implicit reference to its outer class (theSampleActivity, in this case). This reference will persist until the message is processed, thus preventing the activity context from being garbage collected and leaking all of the application's resources. Note that the same is true with the anonymous Runnable class on line 15. Non-static instances of anonymous classes hold an implicit reference to their outer class, so the context will be leaked.

To fix the problem, subclass theHandlerin a new file or use a static inner class instead. Static inner classes do not hold an implicit reference to their outer class, so the activity will not be leaked. If you need to invoke the outer activity's methods from within theHandler, have the Handler hold aWeakReferenceto the activity so you don't accidentally leak a context. To fix the memory leak that occurs when we instantiate the anonymous Runnable class, we make the variable a static field of the class (since static instances of anonymous classes do not hold an implicit reference to their outer class):

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ 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 ); /** * 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() { } }; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 600000 ); // Go back to the previous Activity. finish(); } }

The difference between static and non-static inner classes is subtle, but is something every Android developer should understand. What's the bottom line? Avoid using non-static inner classes in an activity if instances of the inner class outlive the activity's lifecycle. Instead, prefer static inner classes and hold a weak reference to the activity inside.

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. Android情景分析之深入解析system_server
  2. ADT的安装和配置
  3. android获取友盟渠道名以及获取applicati
  4. android之uriMathcer详解及使用
  5. ANdroid网易客户端
  6. Android(安卓)资源类型 整理
  7. Kotlin入门配置与简单实战
  8. Android(安卓)ApiDemos示例解析(179):Vie
  9. android Snapshot
  10. AndroidStudio加快Gradle速度的方法-andr