- Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。
- Handle来创建时会采用当前线程的Looper来构造消息循环系统,那么Handler内部是通过ThreadLocal获取当前线程的Looper
Android的消息机制概述、
- 系统是通过ViewRootImpl对UI操作做了验证,保证UI操作是运行在Ui上的。
- 不允许在子线程中访问uI:是因为Ui的控件不是线程安全地,而如果加上锁机制的话,会让Ui访问的逻辑变得复杂;由于锁机制会阻塞某些线程的执行,会降低了UI的访问的效率
- 三者的联合工作时,Handel的
post方法
将一个Runnable投递到Handler内部的Loopr中处理。也可以通过send方法来完成,它会调用MessageQueue
的enqueueMessage方法
将消息放入消息队列,之后Looper发现有消息来得时候,就会调用handleMessage方法
来处理。
Andorid消息机制机制分析
ThreadLocal工作原理
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定的线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。
使用场景
1. 当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreaLocal。
2. 是复杂逻辑下的对象传递,比如监听器的传递,有些时候一个线程中的任务过于复杂,但我们希望监听器能够贯穿整个线程的执行过程,每个监听器对象都在自己的线程内部存储。
ThreadLocal之所以有这么奇妙的效果
- 因为不同线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自的线程中取出一个数组,然后再从数组中根据当前ThreadLocal的索引去查找出对应好的value值。
ThreadLocal的set方法
public void set(T value){
Thread currentThread = Thread.currentThread();
Value value = values(currentThread);
if(values == null){
values = initializeValues(currentThread);
}
values.put(this, value);
}
- 上面可以看出localValues是通过put()方法将ThreadLocal的值存储到
table数组
中。其中在table组中有个存储规则是ThreadLocal的值在table数组中的位置总是为ThreadLocal的reference字段
标识的对象的下一个位置。
ThreadLocal的get方法
public T get(){
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if(values != null){
Object[] table = values.table;
int index = hash & values.mask;
if(this.reference == table[index]){
retunr table[index + 1];
} else{
values = initializeValues(currentThread);
}
}
return values.getAfterMiss(this);
}
所以他们所操作的对象都是当前线程的localValues对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法,他们对ThreadLocal所做的读/写操作仅限于各自线程的内部
消息队列的工作原理
- 尽管MessageQueue叫消息队列,但是它的颞部实现并不是用的队列,实际上是通过一个
单链表的数据结构
来维护消息列表,单链表在插入和删除上比较有优势。 - 其中next方法时一个无限循环的方法,如果消息队列没有信息,那么next方法会一直阻塞在这里。有消息的时候,会返回这条信息并将其从单链表中移除。
Looper的工作原理
Looper在Android的消息机制中扮演着消息循环的角色。其构造方法如下:
private Looper(boolean quitAllowed){
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper创建过程
- 通过Looper。prepare()即可为当前线程创建一个Looper
- 通过looper来开启消息循环
- 通过quit方法直接退出Looper
注意点:在子线程中,如果手动创建Looper,那么在所有事情完成以后应该
调用quit方法来终止消息循环
,否则这个子线程就会一直处于等待状态。
其中Looper和Handler连接点为msg.target.dispatchMessage(msg)
,这里的msg.target是发送这条消息的Handler对象,在这里切换到指定的线程中去执行。
Handler的工作原理
- Handler工作主要包含消息的发送和接收过程,通过post的一系列方法以及send的一系列方法来实现,而post方法最总是通过send的一系列方法来实现的。
- Handler最总会交给
dispatchMessage方法
调用,而检查的Message的Callback实际上是Handler的post方法所传递的Runnable参数 - Callback可以代替创建Hander的实例而去使用handler
- Handler是必须通过Looper来构造Handler.
public void dispatchMessage(Message msg){
if(msg.callback != null){
//当message是runnable的情况,也就是Handler的post方法传递的参数,这种情况下直接执行runnable的run方法
handleCallback(msg);
} else {
if(mCallback != null){{//如果创建Handler的时候是给Handler设置了Callback接口的实现,那么此时调用该实现的handleMessage方法
if(mCallback.handleMessage(msg)){
return;
}
}
handleMessage(msg);//如果是派生Handler的子类,就要重写handleMessage方法,那么此时就是调用子类实现的handleMessage方法
}
}
public Handler(Looper looper){
this(looper, null, false);
}
主线程的消息循环
- Android的主线程是ActivityThread,主线程入口方法为main,在main方法中是会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()来开启主线程的消息循环
- 线程开启后还需要Handler进行交互,
Hanler就是ActivityThread.H
,内部定义了一组消息类型,其中它包含了四大组件的启动和停止的过程。 - ActivityThread通过ApplicationThread和AMS进行进程间通信