首页 > 代码库 > 从Android Handler内部类到WeakReference的知识关联
从Android Handler内部类到WeakReference的知识关联
Handler:
普通用法:
Handler用于处理和从队列MessageQueue中得到Message。一般我们要重写Handler的handleMessage(Message msg){}方法来处理,如下代码:
public class MainActivity extends Activity { private TextView textView; Handler normalHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Log.i("test",textView.getText().toString()); break; default: break; } }; }; }
问题:
这个时候Handler会被Android SDK中Lint工具检查警告你(左边那个黄色灯泡+叹号):This Handler class should be static or leaks might occur 。
原因:
This Handler class should be static:
(知识点一)为什么静态内部类可以解决这个问题呢?或者说静态内部类和非静态内部类的区别是什么?
举例:class A{int a; static int b class B{} static class C{} } (A是外部类,B非静态内部类,C静态内部类,a普通字段,b静态字段)
1)B非静态内部类:
可以访问A.a和A.b,也就是外部的属性都能方位。因为B隐式的持有A类对象的引用,相当于A的属性
2)C静态内部类:
C只可以访问A.b,不可以方位A.a。为什么?因为C不含有A的引用,它和A类是同一个级别,只不过写到了A类的内部。
本例原因:
Handler匿名内部类,隐式的持有了外部类Activity的引用(这就是为什么你能在handleMessage()中调用MainActivity中TextView等的属性)。--->而以后调
Message message = normalHandler.obtainMessage();
normalHandler.sendMessageAtTime(message , 100*1000);
得到的message中又含有这个Handler的引用(可以看源码)。
在100秒后message被执行,这期间message被放在MessageQueue中,MessageQueue在Looper中,Looper是线程的本地变量。
也就是说MainActivity即使生命周期走完了也不会垃圾回收,为什么?因为Java的垃圾回收机制,就是看一个对象有没有被引用(从线程中的主要对象开始,对象之间的引用形成网状结构,如果有类的对象不在这张网上,就证明它没被引用。这就是数据结构中图的遍历,什么连通子图,非连通子图)。而本文中一个MainActivity被Handler持有引用,Handler被Message持有引用,Message被MessageQueue持有引用,MessageQueue被Looper持有引用,Looper为线程本地变量,线程不被摧毁,它就不会被销毁。
所以即便用户已经切换、退出到别的Activity,MainActivity占有的内存仍旧不会被释放。
解决方案:
打破引用链:
1.Message在100秒后被处理,之后回收Message,然后回收MainActivity。(所以是实际上,你只要不发很长时间的Message也不会有什么问题)
2.使Handler不持有MainActivity的引用,用弱引用WeakReference:(简单讲,就是只有WeakReference引用的对象,垃圾回收将回收该对象,以后再另写一篇引用的文章吧)
正常代码:
MyHandler handler = new MyHandler(this); public static class MyHandler extends Handler { private WeakReference<MainActivity> reference; public MyHandler(MainActivity activity) { reference = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Log.i("test",textView.getText().toString()); break; default: break; } } }
从Android Handler内部类到WeakReference的知识关联