Android开发Handler消息机制深入探究
2016-07-27 15:48
537 查看
提到Handler,大家不免会想到更新主界面或者延时操作。其实handler在安卓开发中扮演的主要角色就是随时更新主界面的。为什么要采用handler来更新主界面呢,这里又要谈到主线程的不安全原则。
我们知道一个应用启动时系统会为其创建一个进程,而每一Activity启动的时候又会形成一个线程,这个线程叫主线程。安卓的主线程是不安全的,因为从主线程中可以创建多个子线程来分配任务,一个activity的所有view都是唯一的,都有唯一的标识,如果在每个子线程中更新view,我们不能预知线程执行结果的先后顺序,也就无法预知什么时候才能更新view,所以造成结果就是view更新时的冲突问题。这也就是为什么从安卓2.0之后官方规定只能在主线程中更新界面了。子线程执行结果后通知主线程更新界面的桥梁便需要handler来帮忙,下面就深入探究一下handle的工作机制。
Handler的消息机制是一个系统,分别由handler,looper,message,messageQueue四个方面组成。先理解几个概念:handler,消息的处理者,负责消息的发送和处理。looper,消息的抽取者,处理消息的前奏。message,所谓的消息,里面包含消息Id。messageQueue,消息队列,handler发送的消息会暂存在消息队列里,然后采用FIFO先进先出的原则进行执行。Activity是在ActivityThread这个类的main方法里构造的,当构造好之后回调了OnCreate方法,之后调用UI线程的Looper.loop(),让looper开始工作,这个函数内部是一个循环,也即是主线程会一直执行下去。有些人可能会问这样下去会不会很耗cpu资源,其实不是这样,UI主线程其实一直处于半活动状态,当有消息来了他就会被唤醒,当没有消息的时候就会阻塞处于休眠状态。一个线程中只能有一个looper,Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。
关系图:
消息生成:
方法1:
第二种写法是直接调用 handler 的发送消息方法发送消息。
发送消息:
在第一个代码片段中我们发现,handler在发送message的时候首先要找到所引用的消息队列。在第二个代码块中我们看到,Message的target设定成自己,目的是为了在处理消息环节中,Message能找到正确的Handler,最后将这个Message纳入到消息队列中。
抽取消息:
这里的looper处于一个死循环,时刻检索消息队列中的消息。
消息的分发:
到这一步也算是最后一步消息即将传递到位,只等回调出来了。
附加说明:
在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象,系统已经帮我们创建了;
在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。所以我们要自行在handler线程中创建一个looper,让他自行的跑起来,这样才能顺利接收和分发我们的消息了。
我们知道一个应用启动时系统会为其创建一个进程,而每一Activity启动的时候又会形成一个线程,这个线程叫主线程。安卓的主线程是不安全的,因为从主线程中可以创建多个子线程来分配任务,一个activity的所有view都是唯一的,都有唯一的标识,如果在每个子线程中更新view,我们不能预知线程执行结果的先后顺序,也就无法预知什么时候才能更新view,所以造成结果就是view更新时的冲突问题。这也就是为什么从安卓2.0之后官方规定只能在主线程中更新界面了。子线程执行结果后通知主线程更新界面的桥梁便需要handler来帮忙,下面就深入探究一下handle的工作机制。
Handler的消息机制是一个系统,分别由handler,looper,message,messageQueue四个方面组成。先理解几个概念:handler,消息的处理者,负责消息的发送和处理。looper,消息的抽取者,处理消息的前奏。message,所谓的消息,里面包含消息Id。messageQueue,消息队列,handler发送的消息会暂存在消息队列里,然后采用FIFO先进先出的原则进行执行。Activity是在ActivityThread这个类的main方法里构造的,当构造好之后回调了OnCreate方法,之后调用UI线程的Looper.loop(),让looper开始工作,这个函数内部是一个循环,也即是主线程会一直执行下去。有些人可能会问这样下去会不会很耗cpu资源,其实不是这样,UI主线程其实一直处于半活动状态,当有消息来了他就会被唤醒,当没有消息的时候就会阻塞处于休眠状态。一个线程中只能有一个looper,Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。
关系图:
消息生成:
方法1:
Message msg = handler.obtainMessage(); msg.arg1 = i; msg.sendToTarget();方法2:
Message msg=new Message(); msg.arg1=i; handler.sendMessage(msg);第一种写法是message 从handler 类获取,从而可以直接向该handler 对象发送消息,减少了内存空间的开辟,节省资源。
第二种写法是直接调用 handler 的发送消息方法发送消息。
发送消息:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在第一个代码片段中我们发现,handler在发送message的时候首先要找到所引用的消息队列。在第二个代码块中我们看到,Message的target设定成自己,目的是为了在处理消息环节中,Message能找到正确的Handler,最后将这个Message纳入到消息队列中。
抽取消息:
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;
这里的looper处于一个死循环,时刻检索消息队列中的消息。
消息的分发:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
到这一步也算是最后一步消息即将传递到位,只等回调出来了。
附加说明:
在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象,系统已经帮我们创建了;
在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。所以我们要自行在handler线程中创建一个looper,让他自行的跑起来,这样才能顺利接收和分发我们的消息了。
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }至此今天我们针对handler,looper,messageQueue有一个中层次的探究,当然还有深一层的探究,等到后续我慢慢的再补充吧。
相关文章推荐
- Android自定义类似ProgressDialog效果的Dialog
- Android二维码扫码--精简版zxing使用教程
- Android无障碍设计简介
- Android之百度云推送(一)如何导入手机apk
- Android自定义属性:format选项之reference
- Android开源工具项目集合
- Rxandroid与MVP的结合(demo)
- Android 创建目录
- Android PendingIntent的理解
- Android PendingIntent的理解
- Android PendingIntent的理解
- Android PendingIntent的理解
- RxJava两步打造华丽的Android引导页
- 【Android】使用Gradle打包时,获取svn的版本号,删除unalign.apk文件,获得版本号,并设定在打包的文件名称中
- android 文件存储
- 浅谈Android中MVP设计模式
- Android提醒Dialog、Toast和Snackbar ---站在巨人的肩膀上学习总结
- Android Chart
- 【Android】使用Jenkins+Gradle+FTP,实现自动打包,自动上传文件至FTP
- Android Listview滑动及渐变动画