在Android的开发过程中,Handler经常被使用到,我们可以通过它的handlerMessage方法来处理一些异步返回的结果。常用到如下代码:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case LOADDBDATA:
// do something when msg.what=0x01
// ...
// ...
break;
default:
break;
}
}
};
这样写可以实现功能,但是在会受到编译器的一个警告
这段警告的大意是:
内容来自:http://blog.csdn.net/atangsir/article/details/48226789
1.当这个App启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper负责管理MessageQueue和Message对象,读取到MessageQueue中的Message之后就会采用sendMessage的方式把消息发送给对应的Handler来处理,Looper接收到一条一条的消息后逐一进行处理,所以主线程中的Looper和App的生命周期一样长。
2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用 Handler#handleMessage(Message)完成消息的正确处理。
3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。
个人觉得大意就是在:上述方式是将handler作为一个匿名内部类使用的,因为java的设计,匿名内部类会持有外部类的引用。且Handler 属于 TLS(Thread Local Storage) 变量, 生命周期和 Activity 是不一致的。假如我们通过postDelay延时发送消息,通知HandlerMessage方法做某些事情,并且在发送消息后finish掉页面。这时因为匿名内部类持有外部类的引用(既Activtiy的引用),而activity已经被finish掉了,此时GC回收垃圾----既不必要的对象时会发现activity的引用还被其他人持有,因为handler是一个TLS对象,它并没有被finish掉,这样就造成了内存的溢出。
解决方式:构建一个静态内部类继承Handler,当声明一个事物是static时,就意味着这个域或方法不会与包含它的那个类的任何对象的实例关联在一起。在Activity中不要使用非静态内部类
static class MyHandler extends Handler {
WeakReference<LauncherActivity> actReference;
MyHandler(LauncherActivity launcherActivity) {
actReference =new WeakReference<LauncherActivity(launcherActivity);
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LauncherActivity activity = actReference.get();
switch (msg.what) {
case Launcher2Login:
Intent intent = new Intent(activity, LoginActivity.class);
activity.startActivity(intent);
activity.finish();
break;
}
}
}
这里使用了弱引用来持有Activity对象,可以参考blog---http://3287316.blog.51cto.com/3277316/1335286