在使用Handler更新UI的时候,我是这样写的:

public class SampleActivity extends Activity {                                                                private final Handler mLeakyHandler = newHandler() {    @Override    public void handleMessage(Message msg) {      // TODO    }  }}

看起来很正常的,但是 Android Lint 却给出了警告:

This Handler class should be static or leaks might occur

意思是说:这个Handler 必须是static的,否则就会引发内存泄露。

其实,对于这个问题,Android Framework 的工程师 Romain Guy 早已经在Google论坛上做出过解释,并且给出了他的建议写法:

I wrote that debugging code because of a couple of memory leaks I 

found in the Android codebase. Like you said, a Message has a 
reference to the Handler which, when it's inner and non-static, has a 
reference to the outer this (an Activity for instance.) If the Message 
lives in the queue for a long time, which happens fairly easily when 
posting a delayed message for instance, you keep a reference to the 
Activity and "leak" all the views and resources. It gets even worse 
when you obtain a Message and don't post it right away but keep it 
somewhere (for instance in a static structure) for later use. 


他的建议写法是:

class OuterClass {                                    class InnerClass {    private final WeakReference mTarget;                                      InnerClass(OuterClass target) {           mTarget = newWeakReference(target);    }                                      void doSomething() {           OuterClass target = mTarget.get();           if(target != null) {                target.do();              }     }}

下面,我们进一步解释一下:

1.Android App启动的时候,Android Framework 为主线程创建一个Looper对象,这个Looper对象将贯穿这个App的整个生命周期,它实现了一个消息队列(Message  Queue),并且开启一个循环来处理Message对象。而Framework的主要事件都包含着内部Message对象,当这些事件被触发的时候,Message对象会被加到消息队列中执行。
2.当一个Handler被实例化时(如上面那样),它将和主线程Looper对象的消息队列相关联,被推到消息队列中的Message对象将持有一个Handler的引用以便于当Looper处理到这个Message的时候,Framework执行Handler的handleMessage(Message)方法。
3.在 Java 语言中,非静态匿名内部类将持有一个对外部类的隐式引用,而静态内部类则不会。

到底内存泄露是在哪里发生的呢?以下面代码为例:

public class SampleActivity extends Activity {                    private final Handler mLeakyHandler = newHandler() {    @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(newRunnable() {      @Override      public void run() { }    }, 60 * 10 * 1000);                      // Go back to the previous Activity.    finish();  }}

当Activity被finish()掉,Message 将存在于消息队列中长达10分钟的时间才会被执行到。这个Message持有一个对Handler的引用,Handler也会持有一个对于外部类(SampleActivity)的隐式引用,这些引用在Message被执行前将一直保持,这样会保证Activity的上下文不被垃圾回收机制回收,同时也会泄露应用程序的资源( views and resources )。


为解决这个问题,下面这段代码中的Handler则是一个静态匿名内部类。静态匿名内部类不会持有一个对外部类的隐式引用,因此Activity将不会被泄露。如果你需要在Handler中调用外部Activity的方法,就让Handler持有一个对Activity的WeakReference,这样就不会泄露Activity的上下文了,如下所示:

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 mActivity;             public MyHandler(SampleActivity activity) {      mActivity = newWeakReference(activity);    }             @Override    public void handleMessage(Message msg) {      SampleActivity activity = mActivity.get();      if(activity != null) {        // ...      }    }  }           private final MyHandler mHandler = newMyHandler(this);           /**   * Instances of anonymous classes do not hold an implicit   * reference to their outer class when they are "static".   */  private static final Runnable sRunnable = newRunnable() {      @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, 60 * 10 * 1000);                 // Go back to the previous Activity.    finish();  }}

总结:

在实际开发中,如果内部类的生命周期和Activity的生命周期不一致(比如上面那种,Activity finish()之后要等10分钟,内部类的实例才会执行),则在Activity中要避免使用非静态的内部类,这种情况,就使用一个静态内部类,同时持有一个对Activity的WeakReference


原文链接:  点这里

更多相关文章

  1. cocos2dx通过Jni调用Android的Java层代码(下)
  2. DownloadManager 文件下载
  3. openssl移植android
  4. Android(安卓)更新ProgressBar
  5. Android实现录屏和截屏功能
  6. Android(安卓)JNI入门第六篇――C调用Java
  7. android 9.0接收静态广播
  8. Android(安卓)库文件的编译(静态和动态库 Android.mk)
  9. Android利用Handler更新主线程UI

随机推荐

  1. android 实现 搜索保存历史记录功能
  2. 在android的Browser中设置User Agent
  3. Android系列教程之四:Android项目的目录结
  4. Android JNI环境搭建及开发入门
  5. Android activity四种启动模式及Flag
  6. 【Android】Android 代码判断当前设备是
  7. Android 布局 LinearLayout与RelativeLay
  8. 关于Android学习要问的一些问题
  9. Android中popWindow弹出菜单的编写
  10. Android(java)学习笔记106:Android XML解析