更多内容,可访问个人博客 www.liangfeizc.com

错误代码

如果在Activiy中通过内部类(Runnable)的方式定义了一个变量runnable,

final Runnable runnable = new Runnable() {    public void run() {        // ... do some work    }};handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10)

因为Runnable不是static类型,所以会有一个包含Activity实例的implicit reference --- Activity.this。

如果Activity在runnable变量run之前(10s内)被finish掉了但是Activity.this仍然存在,那么Activity的对象就不会被GC回收,从而导致memory leak

即使使用一个静态内部类,也不能保证万事大吉。

static class MyRunnable implements Runnable {    private View view;    public MyRunnable(View view) {        this.view = view;    }    public void run() {        // ... do something with the view    }}

假设在runnable执行之前,View被移除了,但是成员变量view还在继续引用它,仍然会导致memory leak

上面的两个例子当中,导致内存泄露的两种用法分别是隐式引用(implicit reference)显式引用(explicit reference)

解决方法

解决隐式引用的方法比较简单,只要使用内部非静态类(non-static inner class)或者 top-level class(在一个独立的java文件中定义的变量)就可以将隐式变为显式,从而避免内存泄露。

如果继续使用非静态内部类,那么就要在onPause的时候手动结束那些挂起的任务(pending task)。

关于如何结束任何,Handler可参考这篇文章中的Canceling a pending RunnableCanceling pending Messages。HandlerThread可参考这篇文章。

解决第二个问题要用到WeakReference,WeakReference的用法可以google一下,简而言之就是:只要还有其他的stronger reference,WeakReference就可以继续引用。

static class MyRunnable implements Runnable {    private WeakReference>View< view;    public MyRunnable(View view) {        this.view = new WeakReference>View<(view);    }    public void run() {        View v = view.get();        if (v != null) {            // ... do something with the view        }    }}

这样一来问题就解决了,美中不足的是每次使用view之前都要做空指针判断。另外一个比较高效的方法就是在onResume中为runnable的view赋值,在onPause中赋值为null。

private static class MyHandler extends Handler {    private TextView view;    public void attach(TextView view) {        this.view = view;    }    public void detach() {        view = null;    }    @Override    public void handleMessage(Message msg) {        // ....    }

总结

在继承Handler或者HandlerThread的时候,

  • 尽量定义一个static类或者top-level类。
  • 如果用到了ui元素,一定要在Activity的生命周期接触之前释放掉。

参考

Asynchronous Android - Steve Liles

更多相关文章

  1. Maven uploadArchives命令报错:Could not deploy to remote repos
  2. 【ubuntu】Ubuntu中Android(安卓)SDK下载跟配置
  3. Android实现自动填充验证码
  4. Windows8下PhoneGap 4 + Android(安卓)Studio 1.0 + VS2013配置
  5. Android(安卓)uevent
  6. 注意:Android中Handler引起的内存泄露
  7. android安全问题(五) 抢先拦截短信 - 结果篇
  8. android 页面布局时定义控件ID时@id/XX和@+id/xx 有什么区别?
  9. 新年过后献上关于Android内存泄漏的种种总结

随机推荐

  1. android tools命名空间
  2. Android学习资料分享
  3. android 去除ScrollVIew拉到尽头时再拉的
  4. Android圆形进度显示控件的SectorProgres
  5. 关于android生命周期那点事
  6. MTK Android Driver :sound
  7. 新添的Activity 要在 manifest 中注册 否
  8. android 设置 源码 修改默认主题为白底黑
  9. [置顶] android 心跳包的分析
  10. Android Permission中英对照