写点什么

Android 源码解析——Handler,看完直接跪服

用户头像
Android架构
关注
发布于: 刚刚

sendMessageAtTime()?方法中需要一个已初始化的?MessageQueue?类型的全局变量?mQueue,否则程序无法继续走下去


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);


}


而?mQueue?变量是在构造函数中进行初始化的,且?mQueue?是成员常量,这说明?Handler?与?MessageQueue?是一一对应的关系,不可更改


如果构造函数没有传入?Looper?参数,则会默认使用当前线程关联的?Looper?对象,mQueue?需要依赖于从?Looper?对象中获取,如果?Looper?对象为 null ,则会直接抛出异常,且从异常信息?Can't create handler inside thread that has not called Looper.prepare()?中可以看到,在向?Handler?发送消息前,需要先调用?Looper.prepare()


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?类中,可以看到,myLooper()?方法是从?sThreadLocal?对象中获取?Looper?对象的,sThreadLocal?对象又是通过?prepare(boolean)?来进行赋值的,且该方法只允许调用一次,一个线程只能创建一个 Looper 对象,否则将抛出异常


static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();


public static @Nullable Looper myLooper() {


return sThreadLocal.get();


}


private static void prepare(boolean quitAllowed) {


//只允许赋值一次


//如果重复赋值则抛出异常


if (sThreadLocal.get() != null) {


throw new RuntimeException("Only one Looper may be created per thread");


}


sThreadLocal.set(new Looper(quitAllowed));


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


}


此处除了因为prepare(boolean)多次调用会抛出异常导致无法关联多个 Looper 外,Looper 类的构造函数也是私有的,且在构造函数中还初始化了一个线程常量?mThread,这都说明了 Looper 只能关联到一个线程,且关联之后不能改变


final Thread mThread;


private Looper(boolean quitAllowed) {


mQueue = new MessageQueue(quitAllowed);


mThread = Thread.currentThread();


}


那么?Looper.prepare(boolean)?方法又是在哪里调用的呢?查找该方法的所有引用,可以发现在?Looper?类中有如下方法,从名字来看,可以猜测该方法是由主线程来调用的,查找其引用


public static void prepareMainLooper() {


prepare(false);


synchronized (Looper.class) {


if (sMainLooper != null) {


throw new IllegalStateException("The main Looper has already been prepared.");


}


sMainLooper = myLooper();


}


}


最后定位到?ActivityThread?类的?main()?方法


看到?main()?函数的方法签名,可以知道该方法就是一个应用的起始点,即当应用启动时, 系统就自动为我们在主线程做好了?Handler?的初始化操作, 因此在主线程里我们可以直接使用?Handler


如果是在子线程中创建?Handler?,则需要我们手动来调用?Looper.prepare()?方法


public static void main(String[] args) {


···


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();


throw new RuntimeException("Main thread loop unexpectedly exited");


}


回到最开始,既然?Looper?对象已经由系统来为我们初始化好了,那我们就可以从中得到?mQueue对象


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()");


}


//获取 MessageQueue 对象


mQueue = mLooper.mQueue;


mCallback = callback;


mAsynchronous = async;


}


mQueue?又是在?Looper?类的构造函数中初始化的,且?mQueue?是?Looper?类的成员常量,这说明 Looper 与 MessageQueue 是一一对应的关系


private Looper(boolean quitAllowed) {


mQueue = new MessageQueue(quitAllowed);


mThread = Thread.currentThread();


}


sendMessageAtTime()?方法中在处理?Message?时,最终调用的是?enqueueMessage()?方法


当中,需要注意?msg.target = this?这句代码,target?对象指向了发送消息的主体,即?Handler?对象本身,即由?Handler?对象发给?MessageQueue?的消息最后还是要交由?Handler?对象本身来处理


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) {


//target 对象指向的也是发送消息的主体,即 Handler 对象


//即由 Handler 对象发给 MessageQueue 的消息最后还是要交由 Handler 对象本身来处理


msg.target = this;


if (mAsynchronous) {


msg.setAsynchronous(true);


}


return queue.enqueueMessage(msg, uptimeMillis);


}


因为存在多个线程同时往同一个 Loop 线程的 MessageQueue 中插入消息的可能,所以?enqueueMessage()?内部需要进行同步。可以看出 MessageQueue 内部是以链表的结构来存储 Message 的(Message.next),根据 Message 的延时时间的长短来将决定其在消息队列中的位置


mMessages?代表的是消息队列中的第一条消息,如果 mMessages 为空,说明消息队列是空的,或者 mMessages 的触发时间要比新消息晚,则将新消息插入消息队列的头部;如果 mMessages 不为空,则寻找消息列队中第一条触发时间比新消息晚的非空消息,并将新消息插到该消息前面


到此,一个按照处理时间进行排序的消息队列就完成了,后边要做的就是从消息队列中依次取出消息进行处理了


boolean enqueueMessage(Message msg, long when) {


//Message 必须有处理者


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) {


IllegalStateException e = new IllegalStateException(


msg.target + " sending message to a Handler on a dead thread");


Log.w(TAG, e.getMessage(), e);


msg.recycle();


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.


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.


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.


if (needWake) {


nativeWake(mPtr);


}


}


return true;


}


下面再看下 MessageQueue 是如何读取 Message 并回调给 Handler 的


在 MessageQueue 中消息的读取其实是通过内部的?next()?方法进行的,next()?方法是一个无限循环的方法,如果消息队列中没有消息,则该方法会一直阻塞,当有新消息来的时候?next()?方法会返回这条消息并将其从单链表中删除


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();


}


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.


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.


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.


for (int i = 0; i < pendingIdleHandlerCount; i++) {


final IdleHandler idler = mPendingIdleHandlers[i];


mPendingIdleHandlers[i] = null; // release the reference to the handler


boolean keep = false;


try {


keep = idler.queueIdle();


} 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.


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.


nextPollTimeoutMillis = 0;


}


}


next()?方法又是通过?Looper?类的?loop()?方法来循环调用的,而?loop()?方法也是一个无限循环,唯一跳出循环的条件就是?queue.next()?方法返回为 null ,细心的读者可能已经发现了,loop()?就是在?ActivityThread?的?main()函数中调用的


因为?next()?方法是一个阻塞操作,所以当没有消息也会导致?loop()?方法一只阻塞着,而当 MessageQueue 一中有了新的消息,Looper 就会及时地处理这条消息并调用?Message.target.dispatchMessage(Message)?方法将消息传回给 Handler 进行处理


/**


  • Run the message queue in this thread. Be sure to call

  • {@link #quit()} to end the loop.


*/


public static void loop() {


final Looper me = myLooper();


if (me == null) {

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android源码解析——Handler,看完直接跪服