一.Android消息机制概述
概念:Android消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。
Handler的概念:Handler是Android消息机制中最主要的运行机制,之所以Android系统会引入Handler,主要原因就是为了解决在子线程中无法访问UI的矛盾。
Android系统为什么不允许在子线程中访问UI?
主要原因就是Android的UI空间并不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。而如果系统对UI控件的访问加上锁机制,则会大大降低UI访问的效率。因此就引入了Handler。
Handler的工作流程:当Handler被创建完毕后,如果它的send()方法被调用,则它首先会去调用MessageQueue的enqueueMessage()方法并且将这个方法放入消息队列中,然后Looper发现又新消息到来时,就会去处理这个消息,最终消息中的Runnable或者Handler的handleMessage()方法就会被调用。
二.Android消息机制分析
1.ThreadLocal的工作原理
概念:ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能够在指定线程中获取到存储的数据,对于其他线程来说则无法获取到数据。
ThreadLocal的内部实现:ThreadLocal是一个泛型类,它的定义为public class ThreadLocal<T>
,而它内部主要是又set()和get()方法组成。
- set方法
public void set(T value){
Thread currentThread = Thread.currentThread();
Vlaues values = values(currentThread);
if(vlaues == null){
values = initializeVlaue(currentThread); //对空值进行初始化
}
values.put(this,value); //存储
}
在set()方法中,首先会通过values方法来获取当前线程中ThreadLocal数据,接着会对使用put()方法对ThreadLocal的值进行存储,在localValues内部有一个数组:private Obkect[] table
,ThreadLocal的值就存在这个table数组中。
- 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]){
return(T) table[index+1];
}
}
return(T) values.getAfterMiss(this);
}
在get()方法中的逻辑就比较清晰,它主要是取出当前线程的localValues对象,如果这个对象为null,那么返回初始值;如果不为null,那就取出它的table数组并找出ThreadLocal的reference对象在table数组中的位置。
从set和get方法中可以看出,ThreadLocal所操作的对象都是当前线程的localValues对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法都仅仅是局限在它们各自线程的内部。
2.消息队列的工作原理
概念:消息队列在Android中指的是MessageQueue,MessageQueue主要包含两个操作:插入和读取,对应的方法分别是enqueueMessage和next。
- enqueueMessage方法
boolean enqueueMessage(Message msg,long when){
...
synchronized(this){
...
msg.markUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if(p == null || when == 0 || when < p.when){
msg.next = p;
needWake = mBlocked;
}
else{
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for( ; ;){
prev = p;
p = p.next;
if(p == null || when < p.when){
break;
}
if(needWake && p.isAsynchronous()){
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
if(needWake){
nativeWake(mPtr);
}
}
return false;
}
在enqueueMessage()方法中主要就是进行的单链表的插入操作。
- next方法
Message next(){
...
int pendingIdleHandleCount = -1;
int nextPollTimeoutMillis = 0;
for( ; ;){
if(nextPollTimeoutMillis != 0){
Binder.flushPendingCommands();
}
nativePollOnce(ptr,nextPollTimeoutMillis);
synchronized(this){
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if(msg != null && msg.target == null){
do{
prevMsg = msg;
msg = msg.next;
}while(msg != null && !msg.isAsynchronous());
}
if(msg != null){
if(now < msg.when){
nextPollTimeoutMillis = (int) Math.min(msg.when - now,Integer.MAX_VALUE);
}
else{
mBlocked = false;
if(prevMsg != null){
prevMsg.next = msg.next;
}
else{
mMessages = msg.next;
}
msg.next = null;
if(false) Lod.v("");
return msg;
}
}
else{
nextPollTimeoutMillis = -1;
}
}
}
}
next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里,如果有新消息到来时,next方法就会返回这条消息并将其从单链表中移除。
3.Looper的工作原理
概念:Looper在消息机制中的主要就是扮演者消息循环的角色,它会不停的从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就会阻塞在那里。
Looper的创建:因为Handler的工作需要Looper,没有Looper的线程就会被报错,在一个线程中创建Looper的方法如下:
new Thread("Thread#2"){
@Override
public void run(){
Looper.prepare(); //创建Looper
Handler handler = new Handler();
Looper.loop(); //开启Looper的消息循环
};
}.start();
除了Looper的的perpare()的方法之外,系统还提供了prepareMainLooper()方法,该方法主要是给主线程,即ActivityThread创建Looper使用的,不过其本质也是通过prepare来实现的。
Looper的退出:Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quitSafely只是设定一个退出标记,只有把消息队列中所有的消息处理完毕之后才会安全的退出。Looper退出后,通过Handler发送的消息会失败。在子线程中,如果手动为其创建了Looper,那么在所有的事情完成之后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待的状态。
4.Handler的工作原理
概念:Handler的工作主要包含消息的发送和接收过程。消息的发送可以通过post以及send的一系列方法来实现(post的一系列方法最终是通过send的以系列方法来实现的);而消息的接收和处理主要是。下面来分别介绍。
消息的发送:Handler消息的发送的典型过程如下:
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg,0);
}
public final boolean sendMessageDelayed(Message msg,long delayMills){
if(delayMills < 0){
delayMills = 0;
}
return sendMessageAtTime(msg,SystemClock.uptimeMills() + delayMills);
}
public boolean sendMessageAtTime(Message msg,long uptimeMills){
MessageQueue queue = mQueue;
if(queue == null){
RunTimeException e = new RunTimeException(this + "sendMessageAtTime() called with no mQueue");
Log.w("");
return false;
}
return enqueueMessage(queue,msg,uptimeMills);
}
private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMills){
msg.target = this;
if(mAsynchronous){
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg,uptimeMills);
}
Handler的发送消息过程结束之后,MessageQueue的next方法就会返回这条信息给Looper,Looper收到消息后就开始处理了,不过最终还是会交由给Handler的dispatchMessage()方法来进行,之后就进入了处理消息阶段。
消息的处理:Handler处理消息的过程如下:
public void dispatchMessage(Message msg){
if(msg.callback != null){
handleCallback(msg);
}
else{
if(mCallback != null){
if(mCallback.handleMessage(msg)){
return;
}
}
handleMessage(msg);
}
}
首先会判断Message的callback是否为null,如果不为null,则会调用handleCallback()方法来处理消息,handleCallback方法的实现如下:
private static void handleCallback(Message message){
message.callback.run();
}
接着还会检查mCallback是否为null,不为null就调用mCallback的handleMessage方法来处理消息,其中Callback是一个接口。最后调用Handler的handleMessage方法来处理消息。
三.主线程的消息循环
过程:Android的主线程就是ActivityThread,主线程的入口方法为main,在main方法中会进行Looper和MessageQueue的创建,以及Looper的开启的操作。
public static void main(String[] args){
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if(sMainThreadHandler == null){
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if(false){
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG,"ActivityThread"));
}
Looper.loop();
}
主线程的消息循环开始了以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的启动和等待等过程。
主线程消息循环模型:主线程通过ApplicationThread和AMS进行进程间的通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到主线程中执行。
网友评论