Android 提供了 Handler 和 Looper 来满足线程间的通信。Handler 先进先出原则。Looper 类用来管理特定线程内对象之间的消息交换 (MessageExchange)。Handler 消息机制可以说是 Android 系统中最重要部分之一,所以,本篇博客我们就来深入解析 Android 中 Handler 消息机制。
为什么系统不允许子线程更新 UI
因为的 UI 控件不是线程安全的。
如果在多线程中并发访问可能会导致 UI 控件处于不可预期的状态,那为什么不对 UI 控件的访问加上上锁机制呢?因为有这么两个缺点:
1. 上锁会让 UI 控件变得复杂和低效
2. 上锁后会阻塞某些进程的执行
对于手机系统来说,这两个缺点是不可接受的,所以最简单高效的方法就是 —— 采用单线程模型来处理 UI 操作。
对开发者而言也不是很麻烦,只是通过 Handler 切换一下访问的线程的就好。
Handler 的简单使用
既然子线程不能更改界面,那么我们现在就借助 Handler 让我们更改一下界面:
主要步骤是这样子的:
1.new 出来一个 Handler 对象,复写 handleMessage 方法
2. 在需要执行更新 UI 的地方 sendEmptyMessage 或者 sendMessage
3. 在 handleMessage 里面的 switch 里面 case 不同的常量执行相关操作
- public class MainActivity extends ActionBarActivity {
- private TextView mTextView;
- private Handler mHandler;
- private static final int UI_UPDATE1 = 0;
- private static final int UI_UPDATE2 = 1;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case UI_UPDATE1:
- mTextView.setText("通过Handler方法1修改UI");
- break;
- case UI_UPDATE2:
- mTextView.setText("通过Handler方法2修改UI");
- break;
- }
- }
- };
- mTextView = (TextView) findViewById(R.id.textview);
- mTextView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Log.d("Test", "点击文字");
- updateUi();
- }
- });
- }
- protected void updateUi() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 方式一和方式二可以达到相同的效果,就是更改界面
- //方式一
- //mHandler.sendEmptyMessage(UI_UPDATE1);
- //方式二
- Message msg = Message.obtain();
- msg.what = UI_UPDATE2;
- mHandler.sendMessage(msg);
- }
- }).start();
- }
- }
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.example.handlerdemo3.MainActivity" >
- <TextView
- android:id="@+id/textview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hello_world"
- android:layout_centerInParent="true"
- android:clickable="true" />
- </RelativeLayout>
安卓的异步消息处理机制就是 handler 机制。
主线程,ActivityThread 被创建的时候就会创建 Looper
Looper 被创建的时候创建 MessageQueue。
也就是说主线程会直接或间接创建出来 Looper 和 MessageQueue。
Handler 的工作机制简单来说是这样的
1.Handler 发送消息仅仅是调用 MessageQueue 的 enqueueMessage 向插入一条信息到 MessageQueue
2.Looper 不断轮询调用 MeaasgaQueue 的 next 方法
3. 如果发现 message 就调用 handler 的 dispatchMessage,dispatchMessage 被成功调用,接着调用 handlerMessage()
ThreadLocal 工作原理
首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过 ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
另外,说 ThreadLocal 使得各线程能够保持各自独立的一个对象,并不是通过 ThreadLocal.set() 来实现的,而是通过每个线程中的 new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过 ThreadLocal.set() 将这个新创建的对象的引用保存到各线程的自己的一个 map 中,每个线程都有这样一个 map,执行 ThreadLocal.get() 时,各线程从自己的 map 中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal 实例是作为 map 的 key 来使用的。
如果 ThreadLocal.set() 进去的东西本来就是多个线程共享的同一个对象,那么多个线程的 ThreadLocal.get() 取得的还是这个共享对象本身,还是有并发访问问题。
我们看一下 ThreadLocal 的 set 方法
- public void set(T value) {
- Thread currentThread = Thread.currentThread();
- Values values = values(currentThread);
- if (values == null) {
- values = initializeValues(currentThread);
- }
- values.put(this, value);
- }
查看 values 方法里面做了什么
- Values values(Thread current) {
- return current.localValues;
- }
通过上面代码我们可以知道,当 values 为空的时候,才调用 initializeValues 方法进行初始化,查看 inheritValues 相关逻辑:
- private void inheritValues(Values fromParent) {
- // Transfer values from parent to child thread.
- Object[] table = this.table;
- for (int i = table.length - 2; i >= 0; i -= 2) {
- Object k = table[i];
- if (k == null || k == TOMBSTONE) {
- // Skip this entry.
- continue;
- }
- // The table can only contain null, tombstones and references.
- Reference> reference
- = (Reference>) k;
- // Raw type enables us to pass in an Object below.
- InheritableThreadLocal key = reference.get();
- if (key != null) {
- // Replace value with filtered value.
- // We should just let exceptions bubble out and tank
- // the thread creation
- table[i + 1] = key.childValue(fromParent.table[i + 1]);
- } else {
- // The key was reclaimed.
- table[i] = TOMBSTONE;
- table[i + 1] = null;
- fromParent.table[i] = TOMBSTONE;
- fromParent.table[i + 1] = null;
- tombstones++;
- fromParent.tombstones++;
- size--;
- fromParent.size--;
- }
- }
- }
其实就是各种赋值 table 数组,进行初始化
最后才是调用 values.put(this, value) 把 ThreadLocal 和 value 一起保存,我们可以看一下 values.put(this, value) 方法
- void put(ThreadLocal key, Object value) {
- cleanUp();
- // Keep track of first tombstone. That's where we want to go back
- // and add an entry if necessary.
- int firstTombstone = -1;
- for (int index = key.hash & mask;; index = next(index)) {
- Object k = table[index];
- if (k == key.reference) {
- // Replace existing entry.
- table[index + 1] = value;
- return;
- }
- if (k == null) {
- if (firstTombstone == -1) {
- // Fill in null slot.
- table[index] = key.reference;
- table[index + 1] = value;
- size++;
- return;
- }
- // Go back and replace first tombstone.
- table[firstTombstone] = key.reference;
- table[firstTombstone + 1] = value;
- tombstones--;
- size++;
- return;
- }
- // Remember first tombstone.
- if (firstTombstone == -1 && k == TOMBSTONE) {
- firstTombstone = index;
- }
- }
- }
可以看出,Threadlocal 的值在 table 数组的存储位置总是 reference 的下一个位置.
接下来,查看 Threadlocal 的 get 方法
Get 方法的逻辑是:通过 values 方法取出当前线程的 localValues 对象,如果为 null,就返回初始值。如果 localValues 不为 null,取出其 table 数组,如果 reference 等于 table 数组 index 角标的值,就在 table[index + 1] 取出其 Threadlocal 值。
MessageQueue 工作原理
MessageQueue 中文翻译就是消息队列,它内部存储了一组信息,存放的是 Message,以队列的形式对外提供了插入和删除的工作(虽然名字叫做队列,但是其内部的 存储结构是单链表)
主要 插入 和 读取 两个操作,这两个操作对应着两个方法:
- 插入(入队) enqueueMessage(Message msg, long when)
- 读取(出队) next()
查看 enqueueMessage 的源码:
- boolean enqueueMessage(Message msg, long when) {
- if (msg.isInUse()) {
- throw new AndroidRuntimeException(msg + " This message is already in use.");
- }
- if (msg.target == null) {
- throw new AndroidRuntimeException("Message must have a target.");
- }
- boolean needWake;
- synchronized (this) {
- if (mQuiting) {
- RuntimeException e = new RuntimeException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- }
- msg.when = when;
- Message p = mMessages;
- 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;
- }
- }
- if (needWake) {
- nativeWake(mPtr);
- }
- return true;
从 enqueueMessage 的实现来看,主要操作就是单链表的插入操作,接下来查看 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;
- }
- }
从上面代码可以得出以下结论:
1.next 方法是一个无限循环的方法,如果消息队列中没有消息,那么 next 方法会一直阻塞
2. 当有新消息到来,next 方法会返回这条消息,并将其从单链表中移除。
Looper 的工作原理
Looper 是一个轮询器,它的作用不断轮询 MessageQueue,当如果有新的消息就交给 Handler 处理,如果轮询不到新的消息,那就自身就处于阻塞状态。
查看 Looper 类的源码,可以发现的他的构造方法里面创建了一个 MessageQueue,然后将当前线程的对象保存起来
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
在 Looper 的构造方法中初始化了一个消息队列 MessageQueue 和一个线程 Thread。从这可看出:一个 Looper 对应着一个消息队列以及当前线程。
当收到消息 Message 后系统会将其存入消息队列中等候处理。至于 Looper,它在 Android 的消息机制中担负着消息轮询的职责,它会不间断地查看 MessageQueue 中是否有新的未处理的消息;若有则立刻处理,若无则进入阻塞。
相信大家一定有遇到过,在子线程中创建 Handler 会报如下错误
解决办法就是 new Handler 的时候加上 Looper.prepare();
而 Looper.prepare() 的内部实现逻辑就是创建一个 Looper
- 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));
- }
线程默认是没有 Looper 的,但是为什么在主线程没有创建的 Looper 就可以使用 Handler?主线程是特别的。主线程,也就是 ActivityThread,当主线程被创建的时候,会调用 Looper 内的 prepareMainLooper 方法,创建 Looper,该方法是专门给主线程创建 Looper 用的。也正因为这点,所以我们在主线程创建了 Handler 就直接能用了。
- public static void prepareMainLooper() {
- prepare(false);
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
由于这个特殊性,Looper 还提供了一个 getMainLooper 方法,使得可以在任何地方获取主线程的 Looper。
- public static Looper getMainLooper() {
- synchronized (Looper.class) {
- return sMainLooper;
- }
- }
接下来,我们看一下 Looper 的退出
Looper 提供了两个方法进行退出操作,分别是 quit 和 quitSafely, 他们调用的是 MessageQueue 的 quit 方法
- public void quit() {
- mQueue.quit(false);
- }
- public void quitSafely() {
- mQueue.quit(true);
- }
MessageQueue 的 quit 方法:
- void quit(boolean safe) {
- if (!mQuitAllowed) {
- throw new IllegalStateException("Main thread not allowed to quit.");
- }
- synchronized (this) {
- if (mQuitting) {
- return;
- }
- mQuitting = true;
- if (safe) {
- removeAllFutureMessagesLocked();
- } else {
- removeAllMessagesLocked();
- }
- // We can assume mPtr != 0 because mQuitting was previously false.
- nativeWake(mPtr);
- }
- }
如果调用 Looper.quit 方法,最终会调用 removeAllMessagesLocked 方法,该方法逻辑:直接遍历所有的消息,并将消息强制回收
- private void removeAllMessagesLocked() {
- Message p = mMessages;
- while (p != null) {
- Message n = p.next;
- p.recycleUnchecked();
- p = n;
- }
- mMessages = null;
- }
如果调用 Looper.quitSafely 方法,最终会调 removeAllFutureMessagesLocked 方法,该方法逻辑:
- void removeCallbacksAndMessages(Handler h, Object object) {
- if (h == null) {
- return;
- }
- synchronized (this) {
- Message p = mMessages;
- // Remove all messages at front.
- while (p != null && p.target == h
- && (object == null || p.obj == object)) {
- Message n = p.next;
- mMessages = n;
- p.recycleUnchecked();
- p = n;
- }
- // Remove all messages after front.
- while (p != null) {
- Message n = p.next;
- if (n != null) {
- if (n.target == h && (object == null || n.obj == object)) {
- Message nn = n.next;
- n.recycleUnchecked();
- p.next = nn;
- continue;
- }
- }
- p = n;
- }
- }
- }
一个无限 for 循环,只有 n.when > now 和 n == null 才会跳出循环,说明是等消息队列中已有的消息处理完毕后,才会跳出,然后执行回收。
Looper 这个类里面最重要的方法就是 loop() 开启消息循环这个方法了,看一下 loop 代码的实现逻辑:
- 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;
- // 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 (;;) {
- Message msg = queue.next(); // might block
- 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.traceBegin(traceTag, msg.target.getTraceName(msg));
- }
- try {
- msg.target.dispatchMessage(msg);
- } 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.
- 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);
- }
- msg.recycleUnchecked();
- }
- }
通过代码我们知道:looper 方法是一个死循环,唯一跳出的循环的方式是 MessageQueue 的 next 方法返回 null,但这几乎不可能,因为在 MessageQueue 的 next 方法中,假如没有消息加入队列,next 方法会一直阻塞,不会返回 null。如果我们不手动调用 quit 或者 quitSafely 方法的话,MessageQueue 的 next 方法是不可能返回 null 的。
当 MessageQueue 没有消息时,next 方法会一直阻塞在那里,因为 MessageQueue 的 next 方法阻塞了,就导致 Looper 的 loop 方法也一直在阻塞了。
这里我们那一分为二的谈,
loop 轮询不到消息:那么处于阻塞状态,然后就没有然后了,除了又轮询到了新的消息
loop 轮到了新的消息:Looper 就会处理消息
1、msg.target.dispatchMessage(msg),这里的 msg.target 就是指 Handler 对象
2、到了最后,Handler 发送的消息又交给了自己的 dispatchMessage 方法来处理了。(这个 dispatchMessage 方法不是 Handler 自己调用时,是与 Handler 相相关的 Looper 间接调用的),这样下来,就成功地将逻辑切换到指定的线程当中去了
Handler 的工作原理
Handler 的主要工作:消息的 发送 和 接收 。Handler 消息发送的形式有 post 和 send 两种。
查看 Handler 中 sendMessage 代码
- public final boolean sendMessage(Message msg)
- {
- return sendMessageDelayed(msg, 0);
- }
sendMessage 调用 sendMessageDelayed
- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
sendMessageDelayed 调用 sendMessageAtTime
- 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);
- }
sendMessageAtTime 调用 enqueueMessage
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
- boolean enqueueMessage(Message msg, long when) {
- 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;
- }
得出结论:Handler 的发送消息仅仅是调用 MessageQueue 的 enqueueMessage 向插入一条信息到 MessageQueue,MessageQueue 就会返回这条消息给 Looper,Looper 会交给 msg.target.dispatchMessage(msg) 方法处理,就进入消息处理阶段。
查看 dispatchMessage 方法
- /**
- * Handle system messages here.
- */
- 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 方法
- private static void handleCallback(Message message) {
- message.callback.run();
- }
Callback 是一个 Runnable 对象,实际上就是 post 方法传递的 Runnable 参数。
其次,检查 mCallback 是否为 null,如果不为 null 就调用 mCallback.handleMessage 方法,查看 mCallback.handleMessage 方法
- public interface Callback {
- public boolean handleMessage(Message msg);
- }
源码中注释已经对 Callback 进行了解释:
可以用来创建一个 Handler 的实例但不需要派生 Handler 的子类
在日常开发中,创建 Handler 最常见的方式就是派生一个 Handler 的子类并重写 handleMessage 方法来处理具体的消息,而 Callback 给我们提供了另外一种方式,不需要派生 Handler 的子类。
最后,调用 Handler 的 handleMessage 方法,这就是我们平时写 Handler 要实现的方法
主线程的消息循环
Android 的主线程就是 ActivityThread,主线程的路口方法是 main 方法,在 main 中系统会通过 Looper.prepareMainLooper() 来创建主线程的 Looper 以及 MessageQueue, 并通过 Looper.loop() 开启主线程消息循环
- public static void main(String[] args) {
- SamplingProfilerIntegration.start();
- // CloseGuard defaults to true and can be quite spammy. We
- // disable it here, but selectively enable it later (via
- // StrictMode) on debug builds, but using DropBox, not logs.
- CloseGuard.setEnabled(false);
- Environment.initForCurrentUser();
- // Set the reporter for event logging in libcore
- EventLogger.setReporter(new EventLoggingReporter());
- Security.addProvider(new AndroidKeyStoreProvider());
- Process.setArgV0("<pre-initialized>");
- 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();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
主线程开始循环后,ActivityThread 还需要一个 Handler 来和消息队列进行交互,这个 Handler 就是 ActivityThread.H
ApplicationThread 通过 binder 与 Ams 通信, 并将 Ams 的调用, 通过 H 类 (也就是 Hnalder) 将消息发送到消息队列, 然后进行相应的操作,H 收到消息后,就会将 ApplicationThread 中逻辑切换到 ActivityThread 中执行,也就是主线程中执行,这个过程就是主线程的消息循环。
至此,Handler 消息机制就分析完毕,如有错漏,欢迎留言指证。
来源: