如何避免Handler引起内存泄露
2016-03-09 11:39
417 查看
错误代码
如果在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 Runnable和Canceling 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的生命周期接触之前释放掉。
相关文章推荐
- linux命令行参数解析学习心得
- 通用JDBC-demo
- Android 自定义 spinner (背景、字体颜色)
- iOS开发中弹窗的方式
- Gnu/Linux系统C编程之 -- 用户和组
- UIImage转换为NSData再转换为NSString实现post发送数据
- eclipse远程debug Java程序
- 如何建立完整可用的安全大数据平台
- 蓝桥杯 算法训练 动态数组使用 大小写转换
- python的moudles文件中__all__作用
- 初步认识Hadoop
- 3月9号
- 启动squid的时候提示 Failed ,FATAL: No port defined
- php注册登录系统简化版
- Android自定义控件之拓展TextView(ExpandTextView)
- AFN框架封装思路(新版本)
- Git常用命令总结
- 学习进度条
- requirejs学习笔记
- 【SSH进阶之路】Hibernate搭建开发环境+简单实例(二)