从Android Handler内部类到WeakReference的知识关联
2016-03-02 11:58
441 查看
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自定义控件—仿仪表盘进度控件ArcProgressBar
- 关于ListView中使用GestureDetector冲突的解决办法
- 真机运行android遭遇Wait for debugging
- Android代码内存优化建议-Android官方篇
- 浅谈android 四大组件 以及mvc mvp
- Android之ListView下拉刷新和上拉加载实现详解(含源码Demo)
- Android Studio之Eclipse工程代码搬家
- <手机控>开发过程记录
- AIDL导入Android Studio
- Android ExpandableListView的基本使用
- Android动画学习笔记-Android Animation
- Activity的启动模式
- 关于Android的一个常见错误:Unable to add window
- Android Studio 虚拟机设置/启动失败之consider using a system image...
- Android Studio 快捷键
- 【Android Exception】android.content.pm.PackageManager$NameNotFoundException
- ubuntu编译android源码出现的问题记录
- Android基础—思维导图
- Android任务和返回栈完全解析,细数那些你所不知道的细节
- Android 360Float悬浮框项目笔记