Handler的作用
Android中从自定义线程切换到UI线程需要用到Handler,向UI线程发送消息需要Handler
Looper
1:Looper属于线程,Looper对象需要贯穿Thread的整个生命周期中,Android系统采用ThreadLocal将Looper对象保存到其所属线程Thread中。
2:Looper的loop()方法实现对MessageQueue的持续监听
ThreadLocal
ThreadLocal的作用是将数据保存到当前线程,以线程为单位。例如有一个很长的流程,在这个流程中需要持续监听进度信息或者某个状态的转换,此时有两个方法定义一个接口将此接口一次传递下去或者将监听接口定义为以静态变量。第一种方法,不好维护,流程太长。第二种方法可行,但是一旦有两个线程,就需要定义两个静态接口变量,如果有N个,那将不可维护。此时就可以用ThreadLocal了,只需要调用ThreadLocal的set()方法将接口保存到对应线程即可。
首先看ThreadLocal的set():
set()方法的作用是获取当前线程Thread的threadLocals字段,如果threadLocals为null,则创建,然后将value保存到当前线程,否则替换对应数据。
在看ThreadLocal的get()方法:
获取ThreadLocal对应的保存到Thread的value,如果没有保存,则返回null,此时调用setInitialValue():
此时调用initialValue()方法,此方法默认返回null,并且我们可以重写此方法,作为初始化操作。
以上就是ThreadLocal的工作原理。
Looper中ThreadLocal的定义如下:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
这样的话所有线程都操作sThreadLocal,通过sThreadLocal将Looper保存到当前线程Thread中
Handler的工作原理
发送消息
public final boolean sendMessage(Message msg;即可发送一条消息。最终会调用到MessageQueue的enqueueMessage(),将数据插入到消息队列之中。
MessageQueue实际上包含一个单向链表,按照Message的执行时间when顺序排序列。enqueueMessage()中代码很简单,就是链表插入节点的过程。这样发送流程就结束了。
Looper对MessageQueue的持续监听
142行,loop()方法调用MessageQueue的next()方法取消息,如果取出消息,164行,则调用Message发送方Handler的dispatchMessage()方法:
如果msg是post发送的Runnable,则调用message.callback.run();run()仍然运行在当前线程中;否则如果Handler设置了Callback mCallback,则调用mCallback.handleMessage()。如果我们在使用Handler时,不想定义重写Handler的handleMessage(),则可以通过设置Callback的形式处理消息。否则就调用handleMessage(),这也是我们平时开发中的一般操作。
MessageQueue的next()方法
next()中的流程很简单,也是一个for循环,如果有消息则返回队头消息,如果没有则continue持续等待,如果调用了Looper的quit()退出,则返回null。
Looper退出
自定义线程的Looper使用完成后一定要调用quit()退出,否则,Looper的loop()中将持续对队列的监听,此时相关对象将无法被回收。调用quit()退出后,MessageQueue的next()返回null,此时Looper的loop()中for循环拿到Message为null时,作为Looper已退出的条件,直接return,for循环结束。至此,Looper彻底退出。
以上就是Looper,MessageQueue,Handler的工作原理。
UI线程消息机制
以上是ActivityThread的main()代码。
1:main()是App应用进程的入口,Looper.prepareMainLooper();创建UI线程的Looper,MessageQueue,并将UI线程Looper特殊保存到sMainLooper字段。并且MainLooper不可以退出,即Looper.quit()会报异常。
2:ActivityThread thread =new ActivityThread();
thread.attach(false);
ActivityThread的作用简单介绍下,该类作为App进程与四大组件Service通过IPC通信的客户端,并接收四大组件Service发送消息的接收方,最终由Instrument执行。
thread.attach(false);
此方法会触发Application的生命周期的执行。有关app进程,从点击桌面icon启动到AMS通知zygote进程fork app进程的流程自己看app的启动流程即可。
3:在ActivityThread的内部定义了一个Handler类型的H类,该类中定义的消息类型主要和四大组件、Application的启动和停止有关。AMS通过IPC流程完成IBinder进程通信:ActivityManagerService->ApplicationThreadProxy->ApplicationThread。然后ApplicationThread会向H发送消息,进而将执行转移到UI线程。
4:Looper.loop();
至此,UI线程的消息机制就介绍完了。
PS:网上有人介绍Handler消息机制时,说自定义线程,消息发送时最终还会将Message发送到UI线程的MessageQueue,这是错误的。所有线程的消息机制都是独立于当前线程的,Looper和其所属线程的关联是通过ThreadLocal来完成的
后面一张会分析普通消息、异步消息、屏障消息,及其用处。
网友评论