本文主要是介绍Android中的消息机制 - 密切协作的 Handler,Looper,MessageQueue,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Android中的消息机制 - 密切协作的 Handler,Looper,MessageQueue
1.消息机制概述
void checkThread() {if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");}}
我们知道在更新ui的时候,程序会去检查当前线程是否是当前线程,也就是 ui 线程,否则就会抛出异常。
2.Android中的消息机制实现
提到Android中的消息机制,不可避免的就要提到handler ,handler作为系统提供给我们使用的上层接口,是我们操作ui的主要交互对象。
2.1.handler的用法
Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
//执行更新ui操作
break;
}
}
};
new Thread(){
public void run() {
//执行复杂的计算逻辑
Message obtain = Message.obtain();
obtain.what = 1;
obtain.obj = "更新ui";
handler.sendMessage(obtain);
};
}.start();
如上,当我们在子线程中计算一个复杂的操作,然后需要更新ui的时候,那么我们可以通过handler的handleMessage方法来更新ui操作,两者密切配合,完成更新操作。 2.2.在子线程中使用handler
new Thread(){public void run() {Handler handler = new Handler();};}.start();
当子线程的run方法执行的时候,我们满怀期待的去new 一个handler 突然就会发现,what a fuck ,竟然报错了
通过异常信息发现我们没有调用 looper.prepare() ,这是什么鬼 ,通过观察源码发现,
new Thread(){public void run() {Looper.prepare();Handler handler = new Handler();};}.start();
好了,到此为止,我们终于可以在子线程中 创建一个handler实例了,注意,这里我说的是创建实例,并不代表这样就可以正常使用了。
2.3.子线程中handler的正确使用姿势
3.Handler,Looper,MessageQueue 之间协作关系和工作流程
图片来源:http://gityuan.com/2015/12/26/handler-message-framework/
以上就是 handler通信机制的流程图,感谢 gitYuan 的图片。
一次handler通信的过程可以分为如下几个步骤
1.handler 通过sendMessage 方法 发出一个message对象,然后将message对象加入内部的MessageQueue中(链表实现)
2.Looper.looper() 通过不停的循环,处理消息 ,然后将message分发出去交给对应的handler处理
3.使用者通过重写handleMessage 方法处理业务逻辑
4.关于threadLocal
threadLocal一个泛型类,通过threadLocal我们可以在指定的线程中保存数据。他可以实现线程隔离,分别为不同的线程保存数据副本,做到互不干扰。
4.1 threadLocal在handler中的使用
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal 为每一个线程保存了一份looper对象实例
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();
}
同时呢,looper又是一个私有的构造方法,也就意外着我们不能够在外部显示的构造looper实例。在上面的例子中,我们通过looper.prepare()在线程中使用handler,
private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}
通过sThreadLocal去获取一个looper对象,如果looper不为空抛出异常(也就说明,每一个线程中只能存在一个looper对象),否则呢 就新增一个looper。
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();}
首先会去获取当前线程的ThreadLocalMap 对象,这个对象中维护了一个Entry数组,entry中有维护了value 对象, 也就是 我们的 looper对象。
5.关于handler的认识和理解
1.每个线程中只能有一个looper对象
2.子线程中使用handler必须首先创建looper
3.一个线程中可以有多个handler对象,message对象维护了分发的handler对象实例,所以多个handler的分发不会有问题
4.threadLocal机制保证了每个线程内部只会维护了一个looper对象
问题: 既然looper维护了一个无限循环的队列,为什么主线程不会因此而假死或者卡死呢 ? 同样求解
6.参考
这篇关于Android中的消息机制 - 密切协作的 Handler,Looper,MessageQueue的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!