安卓基础组件Looper-03java层面的剖析
- IT业界
- 2025-09-13 09:21:02

文章目录 workflow工作线程 准备Looper创建LooperActivity主线程其他情况 `Looper.prepare()`大体流程java申请Loopernew LooperMessageQueue初始化 nativejniNativeMessageQueue `Looper.loop()`大体流程java获取Looper获取msg,处理msg`Looper.loop()``Looper.loopOnce` (已过时) 获取msg 休眠 nativejninative 其它线程 发送msg大体来说准备Handler构造函数重写 handleMessage重要的成员变量 Handler发送Msg准备MsgHandelr发送msg主要函数Handler::sendMessageMessageQueue::enqueueMessagenativeWake (仅作了解) 工作线程中执行唤醒nativejava`MessageQueue::next()`Looper::loop 唤醒后获取MSG处理MSGHandler::dispatchMessageHandler::handleMessage workflow 工作线程 准备Looper
(app主线程中已经准备好了Looper,可以跳过这一节,直接new Handler)
创建Looper,让Looper运行起来。
调用 Looper.prepare() 初始化 Looper
启动轮询器 Looper.loop() 进入循环休眠状态,对queue进行轮询。
(保证main函数一直运行,一直存活)主线程looper不允许退出。
当消息达到执行时间
message queue队列 不为空,取出
message queue队列为空,队列阻塞,
等消息队列调用入队 enqueuer Message方法被调用的时候,唤醒队列。从而取出消息停止阻塞。
创建Looper Activity主线程app主线程中,可以直接new Handler,跳过这一整章。
prepareMainLooper(),Activity创建时 主线程的Looper是已经准备好了的。
// frameworks/base/core/java/android/app/ActivityThread.java public static void main(String[] args) { Looper.prepareMainLooper(); // ... } // frameworks/base/core/java/android/os/Looper.java @Deprecated public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } 其他情况在app子线程 / framework中的线程中,想要需要自己做两件事:
首先 要创建Looper Looper.prepare
之后 让Looper运行起来Looper.loop()死循环
// Looper.prepare(); // 子线程 Handler mReportHandler; mReportHandler = new Handler() { @Override public void handleMessage(Message msg) {} } // Looper.loop(); // 子线程 Looper.prepare() 大体流程Looper.prepare() 首先需要获取当前线程的 Looper
如果有当前线程的Looper,获取该 Looper
如果没有当前线程的Looper,则执行这一步会自动new一个 Looper 并存到线程本地数据区中。
如果涉及创建,则创建Looper过程中的核心内容是:
native层 初始化一个 NativeMessageQueue 对象, NativeMessageQueue 继承自MessageQueue它持有一个Looper指针 初始化 Native 层 Looper 对象将NativeMessageQueue 对象的地址返回给 Java 层。 java层 保存当前线程 Thread 对象。保存创建的 MessageQueue对象(保存有NativeMessageQueue的地址) java 申请Looper从本地线程区获取当前线程的 Looper 对象,没有的话,就初始化一个,并存在线程本地数据区中。
// frameworks/base/core/java/android/os/Looper.java public static void prepare() { prepare(true); } 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)); } // sThreadLocal.get() will return null unless you've called prepare(). @UnsupportedAppUsage static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); new Looper构造函数中:new 一个 Looper 的过程
创建了一个 MessageQueue对象获取到了当前线程 Thread 对象。 // frameworks/base/core/java/android/os/Looper.java private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); //创建MessageQueue对象 mThread = Thread.currentThread(); } MessageQueue初始化MessageQueue 的初始化过程:
// frameworks/base/core/java/android/os/MessageQueue.java MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); // NativeMessageQueue的地址 // 也包含了对epoll的初始化 } // 调用了 native 方法 nativeInit,对应的 JNI 函数如下 private native static long nativeInit(); native jninativeInit 是一个 Native 方法,对应的 JNI 注册函数如下:
// frameworks/base/core/jni/android_os_MessageQueue.cpp static const JNINativeMethod gMessageQueueMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy }, ... }; static struct { jfieldID mPtr; // native object attached to the DVM MessageQueue jmethodID dispatchEvents; } gMessageQueueClassInfo; int register_android_os_MessageQueue(JNIEnv* env) { int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods, NELEM(gMessageQueueMethods)); jclass clazz = FindClassOrDie(env, "android/os/MessageQueue"); gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J"); gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz, "dispatchEvents", "(II)I"); return res; } NativeMessageQueue续上前文,native层这部分的核心内容是
初始化一个 NativeMessageQueue 对象, NativeMessageQueue 继承自MessageQueue它持有一个Looper指针 初始化 Native 层 Looper 对象将NativeMessageQueue 对象的地址返回给 Java 层。 // frameworks/base/core/jni/android_os_MessageQueue.cpp static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue"); return 0; } nativeMessageQueue->incStrong(env); return reinterpret_cast<jlong>(nativeMessageQueue); } // frameworks/base/core/jni/android_os_MessageQueue.cpp class NativeMessageQueue : public MessageQueue, public LooperCallback { private: JNIEnv* mPollEnv; jobject mPollObj; jthrowable mExceptionObj; }; // frameworks/base/core/jni/android_os_MessageQueue.h class MessageQueue : public virtual RefBase { protected: sp<Looper> mLooper; }; // frameworks/base/core/jni/android_os_MessageQueue.cpp // NativeMessageQueue 构造函数 NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) { // 初始化 Native 层的 looper mLooper = Looper::getForThread(); if (mLooper == NULL) { mLooper = new Looper(false); Looper::setForThread(mLooper); } } Looper.loop()Looper.loop()在工作线程执行,MSG的消费,执行,都是在执行该函数的线程中,
(这里的工作线程是指,拥有Looper、处理MSG的线程)
大体流程 Looper::loop() MessageQueue::next MessageQueue::nativePollOnce ---jni--- android_os_MessageQueue_nativePollOnce NativeMessageQueue::pollOnce Looper::pollOnce Looper::pollInner epoll_wait # 进入阻塞初始化工作完成后,看看 Looper.loop() 方法执行的操作:
核心功能就两点:
获取 TLS 存储的 Looper 对象进入无限循环,调用 loopOnce 进入休眠状态 // frameworks/base/core/java/android/os/Looper.java public static void loop() { // 获取 TLS 存储的 Looper 对象 final Looper me = myLooper(); // 进入无限循环, for (;;) { // MessageQueue.next() 获取 Message,可能阻塞 Message msg = queue.next(); // might block // 分发消息,调用 handler 中的回调函数 msg.target.dispatchMessage(msg); } } java 获取Looper获取 TLS 存储的 Looper 对象很好理解。
// frameworks/base/core/java/android/os/Looper.java public static void loop() { // 获取 TLS 存储的 Looper 对象 final Looper me = myLooper(); me.mInLoop = true; //... } public static @Nullable Looper myLooper() { return sThreadLocal.get(); } // sThreadLocal.get() will return null unless you've called prepare(). @UnsupportedAppUsage static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 获取msg,处理msg获取msg、处理 msg 的过程,原先被封装在 loop::loopOnce 中。最终都是调用了MessageQueue.next()
具体,见下一章节。
Looper.loop() // frameworks/base/core/java/android/os/Looper.java public static void loop() { // 进入无限循环, for (;;) { // MessageQueue.next() 获取 Message,可能阻塞 Message msg = queue.next(); // might block // 分发消息,调用 handler 中的回调函数 msg.target.dispatchMessage(msg); } } Looper.loopOnce (已过时)实际上,Looper.loopOnce是从MessageQueue中取出一个msg并执行。
但在使用中,无限循环内Looper.loopOnce被多次调用。因此,实际上也不需要这个封装了。直接使用 MessageQueue.next()获取msg,和 Handler .dispatchMessage 处理msg。
调用 loopOnce 进入休眠状态
核心流程
通过 MessageQueue 的 next 方法拿到一个 Message,
这里可能会阻塞休眠
通过 dispatchMessage 调用 Handler 中的回调方法
// frameworks/base/core/java/android/os/Looper.java private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { // 获取 Message,可能阻塞 Message msg = me.mQueue.next(); if (msg == null) {} // ... try { //分发消息,调用 handler 中的回调函数 msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; // ... msg.recycleUnchecked(); return true; } 获取msg 休眠通过 MessageQueue 的 next 方法拿到一个 Message,这里可能会阻塞休眠。
// frameworks/base/core/java/android/os/Looper.java public static void loop() { // ... // 进入无限循环, for (;;) { // MessageQueue.next() 获取 Message,可能阻塞 Message msg = queue.next(); // might block // 分发消息,调用 handler 中的回调函数 // 但由于阻塞,这里会在 主线程2 唤醒后才调用 // frameworks/base/core/java/android/os/Handler.java // public void dispatchMessage(@NonNull Message msg) { msg.target.dispatchMessage(msg); } }MessageQueue.next()
调用 nativePollOnce 陷入 Native 层,进入休眠状态,
// frameworks/base/core/java/android/os/MessageQueue.java Message next() { final long ptr = mPtr; // 这个指向 NativeMessageQueue 还记得吗 for (;;) { // 陷入 Native 层,进入休眠状态 nativePollOnce(ptr, nextPollTimeoutMillis); //...... } } private native void nativePollOnce(long ptr, int timeoutMillis); native jninativePollOnce 是一个 Native 方法,对应的 JNI 注册函数如下:
// frameworks/base/core/jni/android_os_MessageQueue.cpp static const JNINativeMethod gMessageQueueMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, // ... { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce }, // ... }; static struct { jfieldID mPtr; // native object attached to the DVM MessageQueue jmethodID dispatchEvents; } gMessageQueueClassInfo; int register_android_os_MessageQueue(JNIEnv* env) { int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods, NELEM(gMessageQueueMethods)); jclass clazz = FindClassOrDie(env, "android/os/MessageQueue"); gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J"); gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz, "dispatchEvents", "(II)I"); return res; } native通过传入的指针,获取到 Native 层的 NativeMessageQueue 对象,接着调用 NativeMessageQueue 对象的 pollOnce 方法。
// frameworks/base/core/jni/android_os_MessageQueue.cpp static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); nativeMessageQueue->pollOnce(env, obj, timeoutMillis); }Native 层 Looper 的 pollOnce 函数,pollOnce 内部主要是调用 epoll_wait 来进入休眠状态。
// frameworks/base/core/jni/android_os_MessageQueue.cpp void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) { // ... // 内部调用 epoll_wait 阻塞 mLooper->pollOnce(timeoutMillis); // ... }上面已经调用 Native 层 Looper::pollOnce 函数,从而调用 epoll_wait 来进入休眠状态。
// frameworks/core/core/libutils/Looper.cpp // system/core/libutils/Looper.cpp int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { for (;;) { while (mResponseIndex < mResponses.size()) { const Response& response = mResponses.itemAt(mResponseIndex++); if (ident >= 0) {... return ident;} } if (result != 0) {return result;} // 如果没有 在 Vector<Response> mResponses; 其中有 sp<LooperCallback> callback; // 则进入下面的休眠状态 result = pollInner(timeoutMillis); } } // system/core/libutils/Looper.cpp int Looper::pollInner(int timeoutMillis) { // ... int eventCount = epoll_wait(epollfd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);pollOnce 的具体代码分析可以参考上述Looper - native - pollAll 部分,这里不再重复。
至此,我们的线程就下 cpu,进入休眠状态。
其它线程 发送msg 大体来说初始化一个 Handler 对象,再传入 msg。发送消息大致三步:
初始化一个 Handler 对象,覆写 Handler 的 handleMessage 方法构建一个 Message 对象通过 Handler 的 sendMessage 方法发送消息后续,会执行 handleMessage
准备Handler在使用 Looper 的线程中通常会初始化一个 Handler 对象,重写其handleMessage方法。
构造函数Handler时,需要指定 Looper 意味着于此同时确定了对应的MessageQueue。
// frameworks/base/core/java/android/os/Handler.java public Handler(@NonNull Looper looper) { this(looper, null, false); } public Handler(@NonNull Looper looper, @Nullable Callback callback) { this(looper, callback, false); } public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async, boolean shared) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; mIsShared = shared; } 重写 handleMessage当 Handler.sendMessage 方法调用时,(无论是本线程的Handler还是其它线程的Handler),在MessageQueue中排队后都会调用该Handeler的handleMessage方法。
// new 一个 Handler,覆写 handleMessage 方法 mHandler = new Handler() { public void handleMessage(Message msg) { //定义消息处理逻辑. } }; // 典型的关于Handler/Looper的线程 class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); // 子线程需要,主线程不需要 mHandler = new Handler() { public void handleMessage(Message msg) { //定义消息处理逻辑. Message msg = Message.obtain(); } }; Looper.loop(); // 子线程需要,主线程不需要 } } 重要的成员变量Handler 初始化过程中,要对 Handler 中有两个重要变量进行赋值:
mLooper:当前线程的 LoopermQueue: 当前进程的 MessageQueue public Handler() { this(null, false); } public Handler(@Nullable Callback callback, boolean async) { // 当前线程的 Looper 对象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } // 当前进程的 MessageQueue mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } Handler发送Msg 准备Msg做好以上的准备工作后,准备Message
// 构建一个 Message Message msg = new Message(); // 获知遵循享元模式: Message msg = Message.obtain(); msg.what = 2; msg.obj = "B"; Message msg = mReportHandler.obtainMessage(MSG_SWITCH_TO_SDR_MEMC); mReportHandler.sendMessage(message); // 通过 Handler 的 sendMessage 方法发送消息 mHandler.sendMessage(msg);我们先看看 Message 的初始化过程:
// frameworks/base/core/java/android/os/Message.java 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 sPoolSize--; return m; } } return new Message(); }从缓存 sPool 里面取 Message,如果没有的话就 new 一个 Message。
Handelr发送msg 主要函数子线程 Handler为了发送MSG,归根结底,都是使用了 入队MSG Handler.enqueueMessage()
Handler::sendMessagemHandler.sendMessage(msg) 内部继续对传入的 Message 进行进一步赋值。例如:把handler的this指针,赋值给了 msg 的 target 成员,这样调用时就知道应该执行哪一个Handler对应的函数了。
// frameworks/base/core/java/android/os/Handler.java public final boolean sendMessage(@NonNull Message msg) { ... } public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { MessageQueue queue = mQueue; return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { // 注意这里 msg.target = this; // 把handler的this指针,赋值给了msg的 target 成员 msg.workSourceUid = ThreadLocalWorkSource.getUid(); // 最终调用到 MessageQueue 的 enqueueMessage 方法 return queue.enqueueMessage(msg, uptimeMillis); } MessageQueue::enqueueMessageMessageQueue.enqueueMessage 代码有点长,核心逻辑:
把 Message 插入 mMessages 链表调用 native 方法 nativeWake 唤醒 native 层的 epoll // frameworks/base/core/java/android/os/MessageQueue.java boolean enqueueMessage(Message msg, long when) { // 添加msg到链表 Message p = mMessages; msg.next = p; mMessages = msg; // We can assume mPtr != 0 because mQuitting is false. // 唤醒Looper,进入native if (needWake) { nativeWake(mPtr); } nativeWakenativeWake 最终会调用 native 层 mLooper 的 wake 函数,
private native static void nativeWake(long ptr);向 eventfd 写入数据,唤醒与 eventfd 绑定的 epoll。
// nativeWake 对应的 JNI 函数 static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); nativeMessageQueue->wake(); } void NativeMessageQueue::wake() { mLooper->wake(); } // eventfd 写数据,唤醒 epoll void Looper::wake() { // 大体就是 write(mWakeEventFd.get(), &inc, sizeof(uint64_t)); } // 这个mWakeEventFd就是epoll关注的句柄之一 void Looper::rebuildEpollLocked() { struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); eventItem.data.fd = mWakeEventFd.get(); // 之前陷入阻塞,也是和eventItems有关 int Looper::pollInner(int timeoutMillis) { // ... epoll_wait(epollfd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);接下来我们就来看看 epoll 唤醒以后的流程。
(仅作了解) 工作线程中执行以下仅作了解,一般来说使用时不需要关心。
之前我们 或被动,或主动的在一个/一些线程中调用了 Looper::loop()。
在线程(一般是主线程)中执行Looper.loop(),则这个线程就是“工作线程”。可以认为是MSG的消费者:所有的MSG的消费,执行都是在该线程中,
调用了 Looper::loop() 的线程,会从进程的MessageQueue中取出、处理MSG,并执行Hanlder的重载。
因为 MessageQueue 是线程安全的,所以可以有多个线程调用 Looper::loop(),这些线程并行的处理Hanlder。
唤醒 nativeLooper::pollInner 解除阻塞后,一路上函数调用栈恢复。相对应的,Java 层的 next 方法被唤醒。
Looper::loop() MessageQueue::next MessageQueue::nativePollOnce ---jni--- android_os_MessageQueue_nativePollOnce NativeMessageQueue::pollOnce Looper::pollOnce Looper::pollInner epoll_wait # 解除阻塞 java唤醒后,一般的流程就是从 mMessages 中找个合适的 message 返回,
MessageQueue::next() // frameworks/base/core/java/android/os/MessageQueue.java public final class MessageQueue { Message next() { // ... for (;;) { // 在这个位置陷入 Native 层,进入休眠状态 // 所以也是从这个位置唤醒 nativePollOnce(ptr, nextPollTimeoutMillis); // 从 mMessages 链表中选取一个合适的 message 返回 synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; Looper::loop再继续返回后进入上一层
// frameworks/base/core/java/android/os/Looper.java // frameworks/base/core/java/android/os/Looper.java public static void loop() { // 进入无限循环, for (;;) { // 从这里恢复阻塞 Message msg = queue.next(); // MessageQueue.next() 获取 Message // 分发消息,调用 handler 中的回调函数 msg.target.dispatchMessage(msg); } }代码很多,核心的流程只有两点:
next() 处返回一个合适的 message通过 msg.target.dispatchMessage(msg) 调用 handler 中的回调至此,整个 Looper 流程就走完了。
唤醒后 Looper.loop() # 唤醒后执行如下步骤 MessageQueue.next() # 获取msg Handler.dispatchMessage # 处理msg Handler.handleMessage 获取MSGLooper不断的调用,从消息队列中获取消息使用for循环
// frameworks/base/core/java/android/os/Looper.java /** * 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(); for (;;) { // MessageQueue.next() 获取 Message,可能阻塞 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // 处理MSG,下文会介绍 处理MSG主线程处理,之前传入MessageQueue的MSG,在主线程中执行。
// frameworks/base/core/java/android/os/Looper.java public static void loop() { // ... // 由于阻塞,在 主线程唤醒后 开始处理获得的msg // 分发消息,调用 handler 中的回调函数 msg.target.dispatchMessage(msg); } }Message持有Handler,Handler持有Callback。
// frameworks/base/core/java/android/os/Message.java public final class Message implements Parcelable { @UnsupportedAppUsage // 这个msg.target就是Handler的this指针,是其他线程初始化Msg时自动填入 /*package*/ Handler target; // frameworks/base/core/java/android/os/Handler.java public class Handler { public void handleMessage(@NonNull Message msg) {} final Callback mCallback; public interface Callback { boolean handleMessage(@NonNull Message msg); } } Handler::dispatchMessageHandler的方法 handleMessage dispatchMessage 等,最终会调用到以下方法
// frameworks/base/core/java/android/os/Handler.java /** * Handle system messages here. */ public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); // 1 Runnable run } else { if (mCallback != null) { // 2 final Callback mCallback; if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } private static void handleCallback(Message message) { message.callback.run(); // 1 Runnable callback; } public Handler(@Nullable Callback callback, boolean async) { mLooper = Looper.myLooper(); mQueue = mLooper.mQueue; mCallback = callback; // 2 执行这里的 handleMessage } public void handleMessage(@NonNull Message msg) { // 3 执行子类的重载(通常说的就是这里) } Handler::handleMessage这也是初始化Handler时,需要重写 handleMessage 的原因
在使用 Looper 的线程中通常会初始化一个 Handler 对象:
// new 一个 Handler,覆写 handleMessage 方法 mHandler = new Handler() { public void handleMessage(Message msg) { //定义消息处理逻辑. } };安卓基础组件Looper-03java层面的剖析由讯客互联IT业界栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“安卓基础组件Looper-03java层面的剖析”