Android Hanlder综合
2016-03-01 21:49
344 查看
有些两三年工作经验的同学对于handler还处在滥用的状态,所以写这篇文章总结一下handler的几点。
首先强调,handler不是线程,很多初学者甚至有点经验的都把handler当成线程来看待,以为用上handler就开启线程操作了,这是不对的。还有一种用法是,用上handler就以为一定是在UI线程中操作了,也不太对。
那么Handler是什么?
Handler是一个事件操作的处理对象,在命令模式中是充当命令处理者的角色。它是一个任务的执行者,依附在线程中进行具体的任务处理。它是一个普通的Object对象,在指定的线程中执行它的handleMessage方法而已,跟线程其实并没有太多关系,只是任何方法都需要在线程中运行。
Hanlder不一定在UI线程中执行:
一般Handler都是用来做UI操作的,但并不代表用上Handler就表示一定可以进行UI操作。你可能在非Activity的类的方法中写了这样一句代码:
如果你一不小心在工作线程中调用了xxx()方法,你的app可能会产生崩溃。这里有两个问题,一是创建的handler并无绑定的looper对象或者未开启loop()方法,报错如下:
二是该handler的创建是在工作线程中,即使looper对象是prepared且开启了loop循环,该处代码也会因为loop()方法(也即handler处理消息)不是执行在UI线程中却进行UI操作而报错。如果需要保证在UI线程中执行,handler的创建需在主线程中,或者主动传入主线程的looper对象:
Hanlder使用场景
Handler常见用途有两种:
一是异步线程通知回调主线程事件;
二是发起延时的UI操作任务;
Handler为异步而生,但在一个成熟的app中,应当有独立的异步处理的工具类,这个工具类应是有线程池操作的,而不是随意的使用new thread + handler post方式来进行异步操作,无论从代码整洁性还是可能带来的其它性能问题方面考虑。
Handler的内存泄露问题
这个是android4.0开始,当你使用handler时adt会自动发出可能引起内存泄露的警告。原因是如果你使用handler发送了延迟的消息或者因其它原因导致的handleMessage执行开始之前,activity已经执行了finish()方法,这个时候会由于handler持有外部类activity的引用而导致acitivty无法被GC回收引起内存泄露。你需要在ondestroy()中调用下面这句代码:
当然这句代码可能会忘记添加,所以我更推荐直接使用WeakHandler,它使用弱引用来规避了内存泄露的的问题:https://github.com/badoo/android-weak-handler
由Handler创建消息对象的正确方法
平时创建消息Message可能是直接new message()
官方提示:
推荐使用
Message类中使用了Recycle机制 ,它的obtain方法会复用仓库中暂时无用的message对象,避免重新创建新的对象而造成更多的性能消耗。
首先强调,handler不是线程,很多初学者甚至有点经验的都把handler当成线程来看待,以为用上handler就开启线程操作了,这是不对的。还有一种用法是,用上handler就以为一定是在UI线程中操作了,也不太对。
那么Handler是什么?
Handler是一个事件操作的处理对象,在命令模式中是充当命令处理者的角色。它是一个任务的执行者,依附在线程中进行具体的任务处理。它是一个普通的Object对象,在指定的线程中执行它的handleMessage方法而已,跟线程其实并没有太多关系,只是任何方法都需要在线程中运行。
Hanlder不一定在UI线程中执行:
一般Handler都是用来做UI操作的,但并不代表用上Handler就表示一定可以进行UI操作。你可能在非Activity的类的方法中写了这样一句代码:
public void xxx(){ new Handler().post(new Runnable(){ public void run(){ textView.setText("abc"); } } ); }
如果你一不小心在工作线程中调用了xxx()方法,你的app可能会产生崩溃。这里有两个问题,一是创建的handler并无绑定的looper对象或者未开启loop()方法,报错如下:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
二是该handler的创建是在工作线程中,即使looper对象是prepared且开启了loop循环,该处代码也会因为loop()方法(也即handler处理消息)不是执行在UI线程中却进行UI操作而报错。如果需要保证在UI线程中执行,handler的创建需在主线程中,或者主动传入主线程的looper对象:
new Hanlder(Looper.getMainLooper())
Hanlder使用场景
Handler常见用途有两种:
一是异步线程通知回调主线程事件;
二是发起延时的UI操作任务;
Handler为异步而生,但在一个成熟的app中,应当有独立的异步处理的工具类,这个工具类应是有线程池操作的,而不是随意的使用new thread + handler post方式来进行异步操作,无论从代码整洁性还是可能带来的其它性能问题方面考虑。
Handler的内存泄露问题
这个是android4.0开始,当你使用handler时adt会自动发出可能引起内存泄露的警告。原因是如果你使用handler发送了延迟的消息或者因其它原因导致的handleMessage执行开始之前,activity已经执行了finish()方法,这个时候会由于handler持有外部类activity的引用而导致acitivty无法被GC回收引起内存泄露。你需要在ondestroy()中调用下面这句代码:
mHandler.removeCallbacksAndMessages(null);
当然这句代码可能会忘记添加,所以我更推荐直接使用WeakHandler,它使用弱引用来规避了内存泄露的的问题:https://github.com/badoo/android-weak-handler
由Handler创建消息对象的正确方法
平时创建消息Message可能是直接new message()
官方提示:
the preferred way to get a Message is to call {@link #obtain() Message.obtain()
推荐使用
handler.obtainMessage() or Message.obtain()
Message类中使用了Recycle机制 ,它的obtain方法会复用仓库中暂时无用的message对象,避免重新创建新的对象而造成更多的性能消耗。
相关文章推荐
- 定位Canvas: trying to use a recycled bitmap android.graphics.Bitmap@299c9ae7
- 1.一个小白初次接触Android
- android:很抱歉,XXX已停止运行
- Android杂项
- android oom 分析
- Android 学习资料收集
- android sudio 如何获取sha1与md5值
- win10下androidStudio1.5中NDK环境搭建/安装/使用
- Android中关于assets和raw播放音频视频的实践
- Android的序列化Parcelable接口
- Android,使用Json发送数据中,使用的Java转义字符 KanKan原创
- android 6.0权限全面详细分析和解决方案
- Android 学习笔记(1)
- android开发内存溢出处理记录
- android开发中Rsa加密的使用
- Android Service解析
- android 发送长短信失败的原因
- Adding Action Buttons --1.1.2
- Android中MotionEvent的来源和ViewRootImpl
- Android中如何实现后台执行定时任务