Handler 源码解析
序言:上一篇文章介绍了handler的用法,这次来分析一下handler的实现原理.网上有很多文章对handler 的源码进行分析,我也看了很多,从中收益匪浅,但是很多文章,写的并不能深入我心,所以,我要写一篇最能深的我心的文章.因为自己的才是最好的.哈哈哈哈
一,Handler流程图
首先我们通过一张handler的流程图,来描述一下Message传递的情况:
图中的箭头指向,代表Message的走向.
上边一共涉及到四个类,分别是
- Message : 消息,线程间通讯的数据单元
- MessageQueue : 消息队列,先进先出
- Handler : 处理器,Message发送,和Message最终执行的地方
- Looper : 循环器
传递Message的过程中,还会涉及到其他的几个类,我们提到时在详细说明
我将Handler分为两大模块来讲述,1,初始化 .2.消息传递过程
二.初始化
初始化就是做消息发送前的准备工作,我的在使用的时候,会先初始化一个Handler
1.Handler初始化
上一篇文章介绍到handler初始化的两种方式
方式一:
Handler sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case MSG_SHOW:
((YJSnackbar) message.obj).showView();
return true;
case MSG_DISMISS:
((YJSnackbar) message.obj).hideView(message.arg1);
return true;
}
return false;
}
});
方式二:
Handler mHandler = new Handler()
两种初始化方式对应两大类发送消息的方法
方式一 ->sendMessage()
方式二 -> postMessage()
我们现在就来通过源码分析一下,Handler在初始化的时候,都做了些什么
Handler构造函数
1.先看Handler的构造函数
ps:图是我纯手工码的,效果可能不太完美,大家凑合看吧
从途中我们可以看出,Handler一共有七个构造函数,最终调用到两个,两个构造函数的不同点在于Looper
我们来看看两个构造函数中,都做了什么
第一个:不带Looper 的 Handler(Callback callback, boolean async)
public Handler(Callback callback, boolean async) {
//....
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
因为他不带Looper 所以,通过Looper.myLooper()方法获取mLooper.如果mLooper==null,直接抛异常
我们再来看看Looper.myLooper();做了写些什么
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
这个是Looper类中的一个静态方法,通过sThreadLocal.get()来获取Looper
这个mThreadLocal又是什么呢
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Looper中的一个静态 final变量.
这里我简单的介绍一下ThreadLocad这个类,不然没办法进行后续步骤.
Threadlocal
它是java.lang包里的一个类,代码不多,700+行,想探索的小伙伴,可以自己去看一下代码.
ThreadLocal主要功能是:
/**
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*
* <p>For example, the class below generates unique identifiers local to each
* thread.
* A thread's id is assigned the first time it invokes {@code ThreadId.get()}
* and remains unchanged on subsequent calls.
* </pre>
* <p>Each thread holds an implicit reference to its copy of a thread-local
* variable as long as the thread is alive and the {@code ThreadLocal}
* instance is accessible; after a thread goes away, all of its copies of
* thread-local instances are subject to garbage collection (unless other
* references to these copies exist).
*/
存储在指定线程的数据的存储类,只能在指定的线程中获取.实现了线程隔离.
很多小伙伴看完心中默念:你他喵的这说的是个鬼啊
别着急,我有法宝,让大家秒懂他的含义,秒???.是的秒懂
static ThreadLocal<Integer> mThreadLocal = new ThreadLocal<Integer>();
public static void main(String[] args) {
mThreadLocal.set(1);
System.out.println(""+mThreadLocal.get());
new Thread("线程1") {
@Override
public void run() {
System.out.println(Thread.currentThread().toString());
//线程1中get,输出为null
System.out.println(""+mThreadLocal.get());
}
}.start();
new Thread("线程2") {
@Override
public void run() {
System.out.println(Thread.currentThread().toString());
//先set在get
mThreadLocal.set(2);
System.out.println("get()的x="+mThreadLocal.get());
int x = mThreadLocal.get();
mThreadLocal.set(++x);
System.out.println("set()后的x="+mThreadLocal.get());
}
}.start();
}
输出的结果
1
Thread[线程1,5,main]
null
Thread[线程2,5,main]
get()的x=2
set()后的x=3
可以看出,在不同线程中,Threadloacl.get()的结果是不一样的
主线程中:set=1,所以get = 1
线程1中:没有set,所以get = null
线程2中:set=2, 所以get = 2,在重新set=3 ,所以get=3
我们进入到set()方法中去看一下
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
//从当前线程中获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
//如果map不为空,把value设置给map ,他的key.= this ,就是当前的这个Threadlocal
if (map != null)
map.set(this, value);
else
//如果map为空,创建
createMap(t, value);
}
//初始化ThreadLocalMap ,并且赋值给前线程的threadLocals
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap是ThreadLocal的静态内部类,里边有一个私有变量叫
Entry[] table
而Entry又是ThreadLocalMap 中的一个静态内部类,继承WeakReference的 弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
里边用threadlocal 作为key,存储Object 的value,这就是上一步Threadlocal中用this作为key的原因
在ThreadLocalMap初始化的时候,初始化Entry[] table ,table是个数组,值是16, 也就是说,Threadlocal中,最多存16个数据
private static final int INITIAL_CAPACITY = 16;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
终于说完了Threadlocal,我们重新回到Handler初始化
当handler发现,当前线程中没有Looper,完蛋,直接抛出异常:“Can’t create handler inside thread that has not called Looper.prepare()”);
小伙伴们是不是对这个异常有几分眼熟,是不是当初自己刚用handler时常常出现的一个bug?
也有许多小伙伴们奇怪,这个Looper.prepare()是什么鬼,我在主线程创建Handler时,并没有调用他,为什么也不会抛异常呢?
关于Looper的,小伙伴们别着急,他是Handler机制的核心,我们先跳过他把Handler初始化讲完,在详细的讲解一下
说完Looper的判断接下来说后边的代码
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
顺道也把第二种Handler初始化的方式说了
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* 这个注释很重要,
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
//注意了,looper不能为空,不能
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这就很简单了,赋值给Handler中变量.
Looper就是上文提到的循环器
mQueue就是消息队列
Callback mCallBack 是Handler中的一个接口,有一个回调方法
public interface Callback {
public boolean handleMessage(Message msg);
}
总结一下Handler的初始化
Handler初始化讲解结束,然后将Looper.
今天先写到这里,晚上回去估计没有的更新,明天在写吧
Looper初始化
咱们书接上回,来聊聊Looper的初始化都做了什么
我们打开Looper类,看他的构造函数
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
有且仅有一个私有的构造函数,做了两个事情
- 1:初始化了一个MessageQueue,赋值给mQueue,Handler初始化的时候,就是获取的这个MessageQueue,
- 2: 把当前线程,赋值给mThread
这两个变量都是final 一经赋值,不在改变
构造函数是私有的,那肯定有其他的public方法对外开放啊,可是并没有直接的public方法初始化Looper.
/**
*唯一的初始化Looper的方法,也是私有静态的
*/
private static void prepare(boolean quitAllowed) {
/*Looper有且只能有一个*/
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将初始化的Looper set给sThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}
这个方法在两个地方被调用,
第一个:
/**
这个方法是不是很眼熟,就是Handler初始化的时候,如果Looper.myLooper()等于空时,报的异常,
Can't create handler inside thread that has not called Looper.prepare()
*/
public static void prepare() {
prepare(true);
}
第二个:不能直接用到的,我们在项目中,一般不要用到这方法.
//是一个私有静态对象,
private static Looper sMainLooper; // guarded by Looper.class
public static void prepareMainLooper() {
prepare(false);
/**
同步锁,当变量sMainLooper!=null时,抛出一个异常.
所以在Activity中,如果我们直接使用这个方法就会抛出异常导致程序崩溃,有同学肯定会奇怪,为什么会抛异常,我明明没有调用过,为什么sMainLooper却有值?因为我们的ActivityThread类中已经调用过了,
*/
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
sMainLooper只有一个get方法,没有set,只有在prepareMainLooper时设置.
返回application的主Looper,它存在与主线程.
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
ActivityThread
Looper的初始化基本介绍完了,只留下一个小问题,为什么我们在项目中不能调用prepareMainLooper,还有Handler在主线程初始化时,为什么不用调用Looper的任何一个初始化方法?
小伙伴们可能会喷我:你个傻嗨,这是两个问题.
委屈巴巴,其实这是同一个问题.
答案就在ActivityThread类的main方法中,下边是main方法中的代码,我全部贴上了,
/**
Android也是用java写的,所以肯定也是有main方法的,
这个就是Android程序的起点,Main方法.
如果以后再有人问你,Android中是不是有main方法,就大胆肯定的告诉他,
有!!!
它里边做了很多东西,我们只找关于Handler初始化的代码,找到Looper.prepareMainLooper();
*/
public static void main(String[] args) {
//.......多余的代码省略吧
/**
初始化主线程的Looper,看到了没在这里初始化的主线程的Looper,所以
1>我们在Activity,Service,Broadcast中使用Handler 是不需要初始化的,
2>我们在Android程序中也是不能使用Looper.prepareMainLooper(),因为在程序的Main方法中已经调用过了.
我没有骗你们吧 ,这是同一个问题.
*/
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//这里有一个关于Looper的代码,启动loop开启循环,
Looper.loop();
//然后,直接抛异常,小伙伴看了这句是不是异常懵逼,直接让程序崩溃?这是什么鬼代码,你没有眼花,也不是google的工程师脑袋抽了,这里涉及到另外一个知识点,我们只需要记住,
Android程序都是在Looper.loop()中.比如Activity以及他的生命周期,
throw new RuntimeException("Main thread loop unexpectedly exited");
}
loop:先简单的说一下,等到消息处理时,我们在详细介绍.
loop是一个无线循环,从MessageQueue.next中,获取Message,如果有Message,就处理,没有消息就休眠
我贴出代码,是希望有兴趣的小伙伴可以看看,Android中神秘的mian方法,到底做了些神秘,如果没兴趣,就直接看我中文注释的解释就好了.另外在最后补充一点:
sMainThreadHandler是H extends Handler,里边是用来处理很多我们非常熟悉的LAUNCH_ACTIVITY,
生命周期以及一些其他的消息的
最后,对Looper做个总结:
ActivityThread 中main方法关于Handler的地方:
MessageQueue初始化
非常简单两个变量的赋值
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
MessageQueue是Looper中的变量,Looper线程中唯一的存在,那么等同于一个线程中,也是有且只能有一个MessageQueue.
有一个变量Message mMessage
Message
最后一个初始化的对象,就是我们的消息Message了,Handler机制的最终目的是什么,传递消息啊,而Message就是我们穿的消息单元.只有有了Message,我们才能把消息传递到制定的线程
Message是一个链表,
1:Message可以直接new 因为构造函数是公有的无参构造
2:obtain() :共7个obtain方法,主要是传参不同,最终都是调用无参的obtiain()
/**这几个变量很重要*/
/*package*/ Handler target;//发送消息的Handler
/*package*/ Runnable callback;//处理消息的回调
地址域 ,指向下一个数据域
/*package*/ Message next;//消息链表,指向下一个Message
private static Message sPool;//可复用的Message链表
//sPool链表的最大值50个
private static final int MAX_POOL_SIZE = 50;
/**一个消息队列中消息复用的方法*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;//将链表头取出来,用于返回值,重新使用
sPool = m.next; //将sPool指向链表的第二Message
m.next = null; //清空用于返回的Message的指向
m.flags = 0; // clear in-use flag
sPoolSize--; //将pool的size减1
return m;
}
}
return new Message();
}
mPool复用Message池中的数据是什么时候添加的呢,在Message的recycle()方法中
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) {//如果没有超过最大值50
next = sPool; //将next指向sPool
sPool = this; //将sPool指向this(Message).把this作为链表的头.
sPoolSize++; //size+1
}
}
}
然后呢,我们最Message做个总结:
所有的准备工作终于做完了,可以愉快的发送消息了吗?
不还不能,因为有一个非常重要的步骤还没有启动,那就是Looper.loop
Looper.loop()
大家是否还记得,前边ActivityThread类中的main()方法中,就有这么一句话?
这个方法的做用就是:开启循环器的循环,是必不可少的一部,非常之重要,视为核心
…如果MessageQueue中有Message,处理Message,
如果没有就休眠.
//引入一个新的问题,为什么,主线程中的for循环一直在,却不会ANR
public static void loop() {
final Looper me = myLooper();//获取当前线程的Looper
if (me == null) {//Looper为空,抛出异常
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//获取Looper中的变量MessageQueue
//........省略部分代码
for (;;) {//死循环开启,
Message msg = queue.next(); // might block
if (msg == null) { //如果没有消息,return
// No message indicates that the message queue is quitting.
return;
}
//如果有消息处理消息,先不详细说,这里只说开启循环
}
}
流程大致如下图:
初始化工作全部完成:总结一下初始化流程,共分为三部
- 第一步:创建Looper,同时创建MessageQueue
- 第二步:创建Handler
- 第三步:启动Looper.loop()
第二,第三步顺序可颠倒.
三.发送消息
通过handler发送消息的方法,在上一篇Handler使用方法中,有详细介绍,这里在重新讲一遍.
上一篇文章中用的思维导图,这次用流程图,感觉会更清晰一点.
粗略讲解一下三类发送方法
- 第一类 :sendEmpty方法,共有三个方法,都有一个int what作为参数,在消息处理时,根据what处理消息,初始化一个Message,what赋值给Message.what,然后到sendMessage类方法中,
- 第二类:post方法,共有五种方法,参数都为Runable,然后通过getPostMessage()方法,初始化Message,并且把参数Ruanable赋值给Message.callback
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
最后调用sendMessage方法
- 第三类,sendMessage方法,共有四个方法.
最后统一调用私有方法enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
- 1.将当前handler赋值给Message,target,
- 2.这个设值我们先跳过
- 3.将消息msg加入消息队列queue,并返回结果
在MessageQueue的enqueueMessage(Message msg, long when)方法中又是怎么添加消息到链表呢?
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {//判断,如果msg中的Handler为空,直接抛异常,所以,我们发送的msg,必须有target
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) {//如果消息所在的线程已经被杀死了,就会抛出此异常
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
//释放msg,将此msg加入到Message的缓存池mPool中
msg.recycle();
return false;//返回添加队列结果为fasle
}
msg.markInUse();//标记msg为正在使用中
msg.when = when;//赋值为when
Message p = mMessages;//mMessage为链表的头
boolean needWake;//是否需要唤醒Looper中的无线循环,
if (p == null || when == 0 || when < p.when) {//如果,链表为空,或者,不需要1,延迟2.循环,或者msg的延时小于mMessage的延时,
// New head, wake up the event queue if blocked.
msg.next = p;//将msg的next,指向p
mMessages = msg;//然后将msg设置为链表头,相当于插入msg到链表头,
needWake = mBlocked;//需要唤醒looper中的循环
} else {//其他情况,(链表不为空,需要延迟执行的msg)
// 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.
needWake = mBlocked && p.target == null && msg.isAsynchronous();//是否需要唤醒looper的循环
Message prev; //将msg插入到链表中.
for (;;) {//1:循环,根据when,判断出msg需要插入链表的位置
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;//设置,不需要唤醒,
}
}
//2.插入链表
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {//如果需要唤醒Looper循环
nativeWake(mPtr);//native方法唤醒,这里就不过多介绍了.
}
}
return true;//返回添加msg到queue的结果为true
}
下边是nativeWake(mPtr)的JNI方法
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake(); 【3】
}
void NativeMessageQueue::wake() {
mLooper->wake(); 【4】
}
void Looper::wake() {
uint64_t inc = 1;
// 向管道mWakeEventFd写入字符1
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
发送消息,到此为止.总结:如下图,实在不知道用流程图更加清晰还是用思维图更清晰,就用思维图吧,大家如果觉得不够清晰,请流言,我会在重新做个流程图的.
四.处理消息
消息发送之后到底是怎么处理的呢?怎么把线程切换到了接收线程来处理消息呢?
这个过程有JNI代码在里边,比如MessageQueue中有提到,如果消息需要立即执行,nativeWake()方法唤醒,往信道里写入数据.
JNI层的代码,我们这篇文章不深入讨论,只是大致介绍一下流程.
Looper.loop()方法,我们已经说过是开启无线循环,在看一遍loop()方法吧各位大佬,这次也是删减过得,无关代码我都会清除掉,想看完整的代码就自行去Looper中看吧
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {//无线循环,
Message msg = queue.next(); // might block
/**
如果消息等于空.直接返回.说好的阻塞呢?说好的休眠呢?直接return了?其实阻塞代码在上一步queue.next()中
*/
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));//开始追踪
}
//获取系统启动到现在的时间,不包括息屏状态的时间
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//调用msg中的target ,target是发送msg的Handler,dispathchMessage处理消息
msg.target.dispatchMessage(msg);
//结束时间.处理消息结束的的时间搓
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);//结束追踪
}
}
//msg释放回收等待下次利用
msg.recycleUnchecked();
}
}
MessageQueue 的next方法,都做了什么,才能取到消息链表中的Message呢?
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; //在native方法中使用,
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();//又是一个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) {//消息不为空,消息的target为空
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
//将链表中的此msg移除,移除的msg保存在prevMsg
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {//msg不为空,
if (now < msg.when) {//msg的延迟执行时间,大于现在时间now
// 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) {//如果有被移除队列的没有target的消息,将队列置于pervMsg后
prevMsg.next = msg.next;
} else {//否则,将消息链表的表头,后移一位
mMessages = msg.next;
}
msg.next = null;//清除msg的地址域指向
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();//标记msg正在使用中
return msg; //将msg返回.
}
} else {//如果msg==null,没有可执行的消息
// No more messages.
nextPollTimeoutMillis = -1;
}
}
我带大家看一下nativePollOnce方法里,大致做了什么,以下关于nativePollOnce的内容,来源于于Handler的native层详情
调取信息的调取链如下图:
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
//将Java层传递下来的mPtr转换为nativeMessageQueue
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis); 【3】
}
这里感叹一下,你如果只在java层理解Handler,是无论如何都不能100%完全理解的,循环休眠和时间计算,延迟执行的代码,都在native层.java要想精通,还是要C++精通才行啊.
queue,next()介绍完了,我们获取到了msg 或者在等待获取msg,直到我们获取到msg
我们在回到Looper.loop方法中,
try {
//最终执行代码,用msg中的target调用dispatchMessage()来处理消息.
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
我们看一下Handler中的dispatchMessage方法
/**
* Handle system messages here.
* Handler机制在这里处理消息
*/
public void dispatchMessage(Message msg) {
/**
//如果msg中的变量callback不为空,callback是一个Runable,通过post方法发送的消息都在这里
执行
*/
if (msg.callback != null) {
handleCallback(msg);
} else {
/**
mCallback是Handler中的变量Callback,Callback是一个Handler中的接口
然后需要在Handler初始化的时候传入,但是两个传入Callback参数的
构造函数,是hide的
*/
if (mCallback != null) {//当mCallback不为空的时候,
if (mCallback.handleMessage(msg)) {//如果执行成功,直接返回
return;
}
}
//执行我们重写的handleMessage方法.
handleMessage(msg);
}
}
第一种处理消息的方法:
private static void handleCallback(Message message) {
// 执行Runable的run方法
message.callback.run();
}
最后总结一下消息处理的过程
其中的queue.next方法的流程为:
至此,Handler机制源码解析全部结束,本文是我纯手工打造,除了涉及到的两三个native方法为参考,文中也附上了链接.非常感谢各位的耐心阅读.如有错误之处,请不吝赐教,我一定会及时改正,虚心求教.