优雅地使用Handler,避免内存溢出、空指针
2016-03-31 11:26
375 查看
在Activity中直接创建Handler的内部类,比如这样:
这时IDE会有黄色的提示:
This Handler class should be static or leaks might occur (null) less... (Ctrl+F1)
Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper
or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the
Handler; Make all references to members of the outer class using the WeakReference object.
非静态的内部类会隐式地持有外部类的引用,这会导致外部类对象无法被系统的GC回收。
如果你的Handler是在主线程外的线程创建的,那就没问题。
如果你的Handler就是在主线程创建的,那就应该使用静态内部类+弱引用的方式来持有外部类引用。
举个例子:
你的Handler在子线程执行了耗时操作再sendMessage,或者发送的Message直接就是延时执行的,如:
根据提示,修改如下:
通过静态内部类+弱引用来持有对象,确保Activity能被及时回收掉,在handleMessage时获取对象,再先判空操作,防止空指针异常。
虽然重复代码只有几行,不过还是可以抽取为基类的,使用的时候依然是采用静态内部类来继承基类:
/**
* Handler的封装
* 子类应为静态内部类
*
* @param <T> 外部类
*/
public abstract class BaseHandler<T>
extends Handler {
private final WeakReference<T> mReference;
public BaseHandler(T t) {
super(Looper.getMainLooper());
mReference = new WeakReference<>(t);
}
@Override
public void handleMessage(Message msg) {
T t = mReference.get();
if (t != null) {
handleMessage(t, msg);
}
}
protected abstract void handleMessage(T t, Message msg);
}
外部类使用时,如下所示:
public class MainActivity
extends CoreActivity {
private Handler mHandler = new MyHandler(this);
private static final class MyHandler
extends BaseHandler<MainActivity> {
public MyHandler(MainActivity mainActivity) {
super(mainActivity);
}
@Override
protected void handleMessage(MainActivity mainActivity, Message msg) {
}
}
注:测试时会发现Activity总是不为NULL,那是因为系统没有调用GC回收。
使用DDMS主动调用几次Cause GC就行了。
public class HandlerActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { doSomething(); } }; private void doSomething() {} }
这时IDE会有黄色的提示:
This Handler class should be static or leaks might occur (null) less... (Ctrl+F1)
Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper
or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the
Handler; Make all references to members of the outer class using the WeakReference object.
非静态的内部类会隐式地持有外部类的引用,这会导致外部类对象无法被系统的GC回收。
如果你的Handler是在主线程外的线程创建的,那就没问题。
如果你的Handler就是在主线程创建的,那就应该使用静态内部类+弱引用的方式来持有外部类引用。
举个例子:
你的Handler在子线程执行了耗时操作再sendMessage,或者发送的Message直接就是延时执行的,如:
mHandler.sendEmptyMessageDelayed(1,5000);//5秒后执行如果这时候,用户按了返回键,撤销了这个Activity,就会可能导致内存泄漏,因为mHandler持有了Activity的引用,而Message又持有了Handler的引用,这个Message在MessageQueue中队列,直到时间到了才会被handleMessage。而在这段时间内,Activity是无法被GC回收掉的。
根据提示,修改如下:
public class HandlerActivity extends AppCompatActivity { private SafeHandler mSafeHandler = new SafeHandler(this); /**根据提示实现的Handler*/ private static class SafeHandler extends Handler { private WeakReference<HandlerActivity> mWeakReference; public SafeHandler(HandlerActivity activity) { super(); mWeakReference = new WeakReference<HandlerActivity>(activity); } @Override public void handleMessage(Message msg) { HandlerActivity activity = mWeakReference.get(); if (activity != null) { activity.doSomething(); } } } private void doSomething() {} }
通过静态内部类+弱引用来持有对象,确保Activity能被及时回收掉,在handleMessage时获取对象,再先判空操作,防止空指针异常。
虽然重复代码只有几行,不过还是可以抽取为基类的,使用的时候依然是采用静态内部类来继承基类:
/**
* Handler的封装
* 子类应为静态内部类
*
* @param <T> 外部类
*/
public abstract class BaseHandler<T>
extends Handler {
private final WeakReference<T> mReference;
public BaseHandler(T t) {
super(Looper.getMainLooper());
mReference = new WeakReference<>(t);
}
@Override
public void handleMessage(Message msg) {
T t = mReference.get();
if (t != null) {
handleMessage(t, msg);
}
}
protected abstract void handleMessage(T t, Message msg);
}
外部类使用时,如下所示:
public class MainActivity
extends CoreActivity {
private Handler mHandler = new MyHandler(this);
private static final class MyHandler
extends BaseHandler<MainActivity> {
public MyHandler(MainActivity mainActivity) {
super(mainActivity);
}
@Override
protected void handleMessage(MainActivity mainActivity, Message msg) {
}
}
注:测试时会发现Activity总是不为NULL,那是因为系统没有调用GC回收。
使用DDMS主动调用几次Cause GC就行了。
相关文章推荐
- Gson.toJson()时内存溢出StackOverflowError
- ASP在ACCESS中模糊查询"内存溢出"的解决方法
- Android 异步获取网络图片并处理导致内存溢出问题解决方法
- Android开发笔记之:Handler Runnable与Thread的区别详解
- 基于Java内存溢出的解决方法详解
- tomcat6.0 /7.0安装版内存溢出设置方法
- 关于PHP内存溢出问题的解决方法
- android的消息处理机制(图文+源码分析)―Looper/Handler/Message
- Android消息处理机制Looper和Handler详解
- AsyncTask陷阱之:Handler,Looper与MessageQueue的详解
- Android编程之内存溢出解决方案(OOM)实例总结
- Android编程开发之seekBar采用handler消息处理操作的方法
- Android中Handler消息传递机制
- Android中的Handler与多线程应用实例
- android开发教程之handler异步更新ui
- Android定时器和Handler用法实例分析
- Toast和Handler的间隔使用实例
- Android中AsyncTask与handler用法实例分析
- 深入理解Android中的Handler异步通信机制
- Android加载图片内存溢出问题解决方法