本文基于android 7.1.1的源代码,来对Handler的消息机制进行分析java
Android线程间的消息机制最经常使用的就是用Handler来实现,而Handler的实现还须要借助Looper、MessageQueue、Message这三个类,下图为这4个类之间的关系android
sendMessage
)和处理相应的消息(
handleMessage
);
enqueueMessage
)和从消息池取出消息(
next
);
loop
),按分发机制将消息分发给目标处理者;
在正文开始前,再来普及一些概念
Process : 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操做系统结构的基础。进程之间内存是不一样享的。
Thread :线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。同一进程下,线程共享内存。app
public class MainActivity extends AppCompatActivity {
private static Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//自定义处理
Log.i("TAG","收到的消息:"+msg.what);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessage(message);
}
}).start();
}
}复制代码
上面这段代码应该是最简单的Handler使用例子了。这段代码里面只涉及到了Handler以及Message,并无看到Looper以及MessageQueue。我再给段伪代码让你们好理解。less
public class ActivityThread extends Thread{
private Handler mHandler;
@Override
public void run() {
Looper.prepare(); //【见2.1】
ActivityThread thread = new ActivityThrad();
//创建Binder通道(建立新线程)
thread.attach(false);
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//TODO 自定义处理消息【见3.2】
}
};
Looper.loop(); 【见2.2】
}
}复制代码
上面的代码大体上就至关于咱们demo给出的例子的Looper缺失部分。通常若是咱们在Activity建立前就会把Looper实例好,因此,咱们平常使用Handler时,都没有发觉到Looper的存在。MessageQueue这类咱们放在后面再来跟你们讲。咱们先来看下这个段伪代码作了哪些操做。异步
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */
public static void prepare() {
prepare(true);
}
//quitAllowed 为true的话,在looper运行退出,为false的话,则是Looper不运行退出
private static void prepare(boolean quitAllowed) {
//每一个线程只容许执行一次该方法,第二次执行时线程的TLS已有数据,会抛出异常。
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//给线程的TLS赋值
sThreadLocal.set(new Looper(quitAllowed));
}复制代码
这里的sThreadLocal
实际上是ThreadLocal类型async
ThreadLocal 线程本地存储区(Thread Local Storage ,简称TLS),每一个线程都有本身的私有的本地存储区域,不一样线程之间彼此不能访问对方的TLS区域。 下面来看下ThreadLocal的set
方法和get
方法。ide
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的TLS
ThreadLocalMap map = getMap(t);
if (map != null)
//从新赋值
map.set(this, value);
else
//保存value到当前线程的this
createMap(t, value);
}复制代码
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的TLS
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
//将存储的值返回
return (T)e.value;
}
//不存在这个值,则从新实例ThreadLocalMap,并将this做为key,value为null
return setInitialValue();
}复制代码
这两段代码都涉及ThreadLocalMap这个类,其实这个类是ThreadLocal的内部类。而这个类里面又有内部类Entry,Entry就是做为存储的类型。
ThreadLocal的get()和set()方法操做的类型都是泛型,接着回到前面提到的sThreadLocal变量,其定义以下:函数
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>()
oop
可见sThreadLocal的get()和set()操做的类型都是Looper类型。post
咱们如今再回到上面的prepare的方法,在调用set方法传入的是Looper的构造方法。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //建立MessageQueue对象. 【见4.1】
mThread = Thread.currentThread(); //记录当前线程.
}复制代码
Looper.prepare()方法到此结束,到这里咱们能够了解到,Looper到这里就跟MessageQueue以及Thread创建关系。
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */
public static void loop() {
//获取当前线程的looper实例
final Looper me = myLooper();
//调用loop前必定要先调用prepare()方法,不然会报错
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//将当前线程的Looper中的消息队列MessageQueue
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
//确保在权限检查时基于本地进程,而不是基于最初调用进程
final long ident = Binder.clearCallingIdentity();
for (;;) {//进入loope的主循环
//从消息队列取消息
Message msg = queue.next(); // 可能会阻塞 【见4.1】
if (msg == null) {
// No message indicates that the message queue is quitting.
//没有消息,则退出循环
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//调用Message自带的Handler的dispatchMessage()进行分发消息
msg.target.dispatchMessage(msg);//【见3.1】
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
// 确保分发过程当中identity不会损坏
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//将Message放入消息池
msg.recycleUnchecked();
}
}复制代码
到这里主线程就进行死循环
,这个循环就是不停的取消息。也就是说当一个Activity实例好,Looper这块就已是处于取消息阶段,只要有消息进来,立马触发next取出消息。并且这里的消息不仅仅局限于咱们本身建立的Handler发送过来的消息。其实整个Activity的生命周期也是经过Handler的消息机制维护的,具体的能够去学下Activity的启动源码。这里有个问题,就是这个死循环运行在UI线程却不会致使ANR的发生。是由于 Android应用程序的主线程在进入消息循环过程前,会在内部建立一个Linux管道,这个管道的做用就是使得主线程在消息队列为空时能够进入空闲状态,当有消息来时,再唤醒主线程进行工做。 因此,也能够这么说Handler的底层机制实际上是 Linux的管道技术 ,正是因为这个技术,让发送消息以及处理消息可以运行于在不一样的线程上。
当取到消息时,就会调用Message的Handler成员的dispatchMessage
方法进行分发消息。
咱们先从Handler的构造方法进行分析
// 通常状况咱们都是调用无参的构造方法
public Handler(Callback callback, boolean async) {
//匿名类、内部类或本地类都必须申明为static,不然会警告可能出现内存泄露
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//获取当前线程的Looper对象
//必须先执行Looper.prerare(),对能获取Looper对象,不然会报错
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//获取Looper的消息队列
mQueue = mLooper.mQueue;
//回调方法
mCallback = callback;
//设置消息是否为异步方式
mAsynchronous = async;
}复制代码
这里能够看出,Handler的MessageQueue由Looper决定,而且Handler所在的线程也是由Looper决定的。
/** * Handle system messages here. */
public void dispatchMessage(Message msg) {
//msg的callback不为空,就回调msg的callback方法
if (msg.callback != null) {
handleCallback(msg);
} else {
//handler自己的mCallback不为空,也便是有参构造函数里面传入
//回调mCallbackd的handleMessage方法
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//前二者不知足状况下,调用handleMessage方法
handleMessage(msg);
}
}复制代码
从上面分发机制能够看出,Message自己的回调优先级是最高的,而Handler自己的方法级别是最低的。因此按照优先级从高到低的排序:
一、Message的回调方法:msg.callback.run()
二、Handler的回调方法:Handler.mCallback.handleMessage(msg)
三、Handler的默认方法:Handler.handleMessage(msg)
咱们日常使用最多的方法实际上是Handler自身的HandleMessage方法,到这里咱们已经大体了解到从消息队列里面取到消息,而且将消息分发到相应的Handler进行处理。这里已经讲完消息机制的后半段,接着来分析消息机制的前半段-发送消息到消息队列。
public final boolean sendMessage(Message msg) {
//延时为0
return sendMessageDelayed(msg, 0);
}复制代码
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}复制代码
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) {
//将当前的Handler赋值给Message
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);【见4.2】
}复制代码
这边特地列出这么多个方法,就是为了说明消息的添加是MessageQueue的enqueueMessage
执行的。咱们再来看看Handler其余一些经常使用的方法,是如何将消息传递过去的。
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}复制代码
public final boolean postDelayed(Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}复制代码
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();【见5.1】
m.callback = r;
return m;
}复制代码
从最后一个方法里面能够看出,利用Handler的post、postDelayed方法,最终消费的是Message的回调方法callback,这个按照3.1的分发机制能够得出。
咱们再来看下咱们的demo给出的方法又是怎么实现的
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}复制代码
从这里能够看出,post跟send方法的区别在于post方法须要传入Runnable
,而send的不须要,最终致使消息的消费位置不同。
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) { //当消息循环已经退出,则直接返回
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//阻塞操做,当等待nextPollTimeoutMillis时长,或者消息队列被唤醒,都会返回
//native方法
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
//当消息Handler为空时,查询MessageQueue中的下一条异步消息msg,则退出循环。
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
//当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
//当消息队列为空,或者是消息队列的第一个消息时
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
//没有idle handlers 须要运行,则循环并等待。
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
//只有第一次循环时,会运行idle handlers,执行完成后,重置pendingIdleHandlerCount为0.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
//去掉handler的引用
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle(); //idle时执行的方法
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
//重置idle handler个数为0,以保证不会再次重复运行
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
//当调用一个空闲handler时,一个新message可以被分发,所以无需等待能够直接查询pending message.
nextPollTimeoutMillis = 0;
}
}复制代码
上面的代码主要的工做就是取出消息,可是真正的工做是在Native层实现的,调用nativePollOnce方法,实现与Native层的通讯。这里咱们不对Native层的实现进行深究,有兴趣的可自行查阅资料了解。后期我也会写关于Native层的实现机制。
boolean enqueueMessage(Message msg, long when) {
//Message的target必须不能为空
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {//正在退出时,回收msg,加入消息池
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle(); 【见5.2】
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// p为null(表明MessageQueue没有消息)或者msg的触发时间是队列中最先的
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
//将消息按时间顺序插入到MessageQueue。正常状况不须要唤醒,除非消息队列存在barrier,而且同时Message是队列中最先的异步消息
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; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
//消息没有退出,咱们认为此时mPtr != 0
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}复制代码
看到这里,咱们能够了解到消息的产生以及添加到队列中去。回到上面写的Demo,handler.sendMessage
到这里就结束了,也就是说这个新建的线程到此就没了。接下来就要唤醒主线程了,这个唤醒主要是唤醒【4.1】说起到的nativePollOnce
方法;当有消息入队以后,nativePollOnce方法就会被调用,而后就开始分发消息了。那么整个Handler的消息机制就走完了。
public static Message obtain() {
synchronized (sPoolSync) {
//消息池不为空
if (sPool != null) {
取出队列头
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
//消息池数量减1
sPoolSize--;
return m;
}
}
return new Message();
}复制代码
这个方法是不少人都推荐调用的,而不是调试Message的构造方法。由于这个是重复利用消息池的空闲消息,提升性能。
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}复制代码
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
//将没用的Message回收到消息池里
next = sPool;
sPool = this;
sPoolSize++;
}
}复制代码
本文从一开始构建循环体Looper、从MessageQueue取出消息到Handler消费消费的过程,而后再对Handler发送消息,紧接着消息入队列这一过程的分析。
Looper在初始化的时候会跟当前所在的线程绑定,而且实例化消息队列MessageQueue。而Handler在实例化的时候,若是没有指定looper的话,默认调用会从当前线程的TLS中取出Looper。因此实例Handler以前,一定是调用了Looper.prepare的。而且结合管道技术,实现一个线程负责取消息,另一个线程负责添加消息。实现了线程间的通讯。
仍是用一张图来总结整个消息机制吧。
一、Handler的sendMessage将Message送到MessageQueue中,此时触发管道(Pipe)唤醒另一端开始读数据
二、MessageQueue的next返回Message,并由Message的Handler成员调用dispatchMessage将Message进行处理(消费)
三、Looper在调用loop后就一直处于等待状态,一直到有Message到来,并将其唤醒,而后再将Message发出去