面试必备:ThreadLocal+Looper+Handler
文章目录
一、Handler使用与概述
1.1使用步骤
1.2Handler的使用背景
二、Android消息机制分析
2.1 ThreadLocal
2.2 messageQueue
2.3 Looper
2.4 Handler
三、主线程的消息机制
Handler是消息机制的上层接口,开发中基本只用和Handler交互即可。Handler可以将一个任务切换到Handler指定的线程中执行。如在用Handler在子线程更新UI。
Android消息机制主要就是Handler的运行机制。Handler的运行还依赖MessageQueue、Looper,及Looper内部使用到的ThreadLocal。
MessageQueue是消息队列,用于存放Handler发送的消息,实际是单链表的结构。
Looper会在消息队列中无限循环的查找消息,有消息就取出,没有就等待。
ThreadLocal本质作用是在每个线程中存储数据。在Looper中的作用就是给每个线程存Looper实例。因为我们知道,创建Handler时是需要线程的Looper实例的,而非UI线程默认是没有Looper的。
一、Handler使用与概述
1.1使用步骤
在任务执行的线程,使用Looper.prepare()来给线程创建Looper实例。
在任务执行的线程,创建Handler实例。
在任务执行的线程,使用Looper.loop()开启消息循环。
在任务发出的线程,使用Handler实例发送消息。
举个例子🌰
如下所示,点击按钮,在主线程发送消息,就会在子线程执行。
(这个例子为了完整展示使用步骤,所以在子线程创建了handler,在主线程发送和消息。通常实际我们使用是在主线程创建handler,在子线程发送消息然后再主线程执行UI的更新,而主线程默认是有Looper并开启的,所以一般不需要第一步和第三部。)
1 @Override
2 protected void onCreate(Bundle savedInstanceState) {
3 super.onCreate(savedInstanceState);
4 setContentView(R.layout.activity_main);
5
6 testHandler();
7 }
8
9 private void testHandler() {
10
11 new Thread(new Runnable() {
12 @Override
13 public void run() {
14 //1、准备looper,即threadLocal<Looper>.set(new Looper())
15 Looper.prepare();
16
17 //2、创建handler实例
18 // 这个重写了handleMessage,handler是属于Handler的子类的实例
19 mHandler = new Handler() {
20 @Override
21 public void handleMessage(Message msg) {
22 super.handleMessage(msg);
23 Log.i(TAG, "child thread, handleMessage: what="+msg.what);
24 }
25 };
26
27 //3、looper启动,sThreadLocal.get()拿到looper,拿到queue,开始queue.next
28 Looper.loop();
29 }
30 }).start();
31 }
32
33 public void onClick(){
34 //4.2、handler.sendMessage发送消息,queue.enqueueMessage(msg),即消息入队列。
35 Log.i(TAG, "main thread, sendMessage");
36 Message message = Message.obtain();
37 message.what = 100;
38 mHandler.sendMessage(message);
39 }
1.2Handler的使用背景
Handler可以将子线程中更新UI的任务切换到主线程。为什么要切换呢?我们知道,UI的访问只能在主线程进行。子线程访问UI就会出现异常,因为在ViewRootImpl中对线程做了校验,只有创建了这个View树的线程,才能访问这个view。 一般情况创建View的线程就是主线程,即UI线程,所以子线程访问会异常。
1 void checkThread() {
2 if (mThread != Thread.currentThread()) {
3 throw new CalledFromWrongThreadException(
4 "Only the original thread that created a view hierarchy can touch its views.");
5 }
6 }
而且,UI线程一般不能做耗时操作,不然会发生ANR。所以当 在子线程做完耗时操作后 又需要更新UI,这时就需要用到Handler了。那为啥一定要用checkThread()保证不让子线程访问UI呢?因为UI控件不是线程安全的。那为啥不加锁呢?一是加锁会让UI访问变得复杂;二是加锁会降低UI访问效率,会阻塞一些线程访问UI。所以干脆使用单线程模型处理UI操作,使用时用Handler切换即可。
二、Android消息机制分析
前面说了,Android消息机制包含几个概念:Handler、MessageQueue、Looper、Looper内部使用到的ThreadLocal。下面详细介绍下。
2.1 ThreadLocal
外界想要在不同thread中存值,就可以threadLocal = new ThreadLocal,然后在不同线程中threadLocal.set(value)就可以了,获取值用threadLocal.get() 。
举个例子🌰,下面例子中 先只看booleanThreadLocal,在主线程设置true,a线程设置false,b线程设置null,然后每个线程都打印 booleanThreadLocal.get()的结果,发现每个线程get的值是不同的,是在每个线程中set的值。这就是神奇之处,同样的booleanThreadLocal.get(),所在线程不同,结果就不同。
1 ThreadLocal<Boolean> booleanThreadLocal = new ThreadLocal<>();
2 ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<>();
3
4 booleanThreadLocal.set(true);
5 integerThreadLocal.set(0);
6 Log.i(TAG, "testThreadLocal: main thread, boolean= "+booleanThreadLocal.get());
7 Log.i(TAG, "testThreadLocal: main thread, int = "+integerThreadLocal.get());
8
9 new Thread(new Runnable() {
10 @Override
11 public void run() {
12 booleanThreadLocal.set(false);
13 integerThreadLocal.set(1);
14 Log.i(TAG, "testThreadLocal: a thread, boolean="+booleanThreadLocal.get());
15 Log.i(TAG, "testThreadLocal: a thread, int = "+integerThreadLocal.get());
16 }
17 }).start();
18
19 new Thread(new Runnable() {
20 @Override
21 public void run() {
22 booleanThreadLocal.set(null);
23 integerThreadLocal.set(2);
24 Log.i(TAG, "testThreadLocal: b thread, boolean="+booleanThreadLocal.get());
25 Log.i(TAG, "testThreadLocal: b thread, int = "+integerThreadLocal.get());
26 }
27 }).start();
结果:
12020-01-08 10:15:38.623 8976-8976/com.hfy.demo01 I/hfy: testThreadLocal: main thread, boolean= true
22020-01-08 10:15:38.623 8976-8976/com.hfy.demo01 I/hfy: testThreadLocal: main thread, int = 0
32020-01-08 10:15:38.624 8976-9226/com.hfy.demo01 I/hfy: testThreadLocal: a thread, boolean=false
42020-01-08 10:15:38.624 8976-9226/com.hfy.demo01 I/hfy: testThreadLocal: a thread, int = 1
52020-01-08 10:15:38.626 8976-9227/com.hfy.demo01 I/hfy: testThreadLocal: b thread, boolean=null
62020-01-08 10:15:38.626 8976-9227/com.hfy.demo01 I/hfy: testThreadLocal: b thread, int = 2
下面看下ThreadLocal的get()、set()方法。
1 /**
2 * Returns the value in the current thread's copy of this
3 * thread-local variable. If the variable has no value for the
4 * current thread, it is first initialized to the value returned
5 * by an invocation of the {@link #initialValue} method.
6 *
7 * @return the current thread's value of this thread-local
8 */
9 public T get() {
10 Thread t = Thread.currentThread();
11 ThreadLocalMap map = getMap(t);
12 if (map != null) {
13 ThreadLocalMap.Entry e = map.getEntry(this);
14 if (e != null) {
15 @SuppressWarnings("unchecked")
16 T result = (T)e.value;
17 return result;
18 }
19 }
20 return setInitialValue();
21 }
22
23 /**
24 * Variant of set() to establish initialValue. Used instead
25 * of set() in case user has overridden the set() method.
26 *
27 * @return the initial value
28 */
29 private T setInitialValue() {
30 T value = initialValue();
31 Thread t = Thread.currentThread();
32 ThreadLocalMap map = getMap(t);
33 if (map != null)
34 map.set(this, value);
35 else
36 createMap(t, value);
37 return value;
38 }
get():获取当前线程的ThreadLocalMap,这里可以先理解成普通 键值对的Map。然后传入threadLocal实例,获取键值对Entry,然后获取Entry的value。如果map为空或value为空则会初始化map、value。
1 /**
2 * Sets the current thread's copy of this thread-local variable
3 * to the specified value. Most subclasses will have no need to
4 * override this method, relying solely on the {@link #initialValue}
5 * method to set the values of thread-locals.
6 *
7 * @param value the value to be stored in the current thread's copy of
8 * this thread-local.
9 */
10 public void set(T value) {
11 Thread t = Thread.currentThread();
12 ThreadLocalMap map = getMap(t);
13 if (map != null)
14 map.set(this, value);
15 else
16 createMap(t, value);
17 }
18 /**
19 * Create the map associated with a ThreadLocal. Overridden in
20 * InheritableThreadLocal.
21 *
22 * @param t the current thread
23 * @param firstValue value for the initial entry of the map
24 */
25 void createMap(Thread t, T firstValue) {
26 t.threadLocals = new ThreadLocalMap(this, firstValue);
27 }
set()中也是获取当前线程的ThreadLocalMap,然后ThreadLocal实例作为key, 和value一起设置给map。没有map就去创建并把value初始化进去。
我们再去看下Thread,有个默认为空的ThreadLocalMap实例threadLocals。
1 /* ThreadLocal values pertaining to this thread. This map is maintained
2 * by the ThreadLocal class. */
3 ThreadLocal.ThreadLocalMap threadLocals = null;
那ThreadLocalMap是啥呢?ThreadLocalMap是ThreadLocal的内部类,作用类似Map,内部有个Entry[]的属性table。所以上面看的get、set方法就是对ThreadLocalMap的Entry[]取和存
。下面详细看下。
1 /**
2 * Construct a new map initially containing (firstKey, firstValue).
3 * ThreadLocalMaps are constructed lazily, so we only create
4 * one when we have at least one entry to put in it.
5 */
6 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
7 table = new Entry[INITIAL_CAPACITY];
8 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
9 table[i] = new Entry(firstKey, firstValue);
10 size = 1;
11 setThreshold(INITIAL_CAPACITY);
12 }
13
14 /**
15 * Get the entry associated with key. This method
16 * itself handles only the fast path: a direct hit of existing
17 * key. It otherwise relays to getEntryAfterMiss. This is
18 * designed to maximize performance for direct hits, in part
19 * by making this method readily inlinable.
20 *
21 * @param key the thread local object
22 * @return the entry associated with key, or null if no such
23 */
24 private Entry getEntry(ThreadLocal<?> key) {
25 int i = key.threadLocalHashCode & (table.length - 1);
26 Entry e = table[i];
27 if (e != null && e.get() == key)
28 return e;
29 else
30 return getEntryAfterMiss(key, i, e);
31 }
32
33 /**
34 * Set the value associated with key.
35 *
36 * @param key the thread local object
37 * @param value the value to be set
38 */
39 private void set(ThreadLocal<?> key, Object value) {
40
41 // We don't use a fast path as with get() because it is at
42 // least as common to use set() to create new entries as
43 // it is to replace existing ones, in which case, a fast
44 // path would fail more often than not.
45
46 Entry[] tab = table;
47 int len = tab.length;
48 int i = key.threadLocalHashCode & (len-1);
49
50 for (Entry e = tab[i];
51 e != null;
52 e = tab[i = nextIndex(i, len)]) {
53 ThreadLocal<?> k = e.get();
54
55 if (k == key) {
56 e.value = value;
57 return;
58 }
59
60 if (k == null) {
61 replaceStaleEntry(key, value, i);
62 return;
63 }
64 }
65
66 tab[i] = new Entry(key, value);
67 int sz = ++size;
68 if (!cleanSomeSlots(i, sz) && sz >= threshold)
69 rehash();
70 }
使用Entry[] 存多个threadLocal-value键值对,数组下标index与是ThreadLocal 实例的hashCode相关。而ThreadLocalMap唯一实例是createMap(Thread t, T firstValue)赋给Thread的变量threadLocals。
例如 线程A threadLocalMap的table[] 可以存储 int、String、boolean类型的3个键值对threadLocal-int, threadLocal-String、threadLocal-Boolean。还是上面的例子。
(常规的HashMap的键值得类型是固定的;threadLocalMap的key是ThreadLocal,value是T,即可以存多种类型的value)
1 ThreadLocal<Boolean> booleanThreadLocal = new ThreadLocal<>();
2 ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<>();
3
4 booleanThreadLocal.set(true);
5 integerThreadLocal.set(0);
6 Log.i(TAG, "testThreadLocal: main thread, boolean= "+booleanThreadLocal.get());
7 Log.i(TAG, "testThreadLocal: main thread, int = "+integerThreadLocal.get());
8
9 new Thread(new Runnable() {
10 @Override
11 public void run() {
12 booleanThreadLocal.set(false);
13 integerThreadLocal.set(1);
14 Log.i(TAG, "testThreadLocal: a thread, boolean="+booleanThreadLocal.get());
15 Log.i(TAG, "testThreadLocal: a thread, int = "+integerThreadLocal.get());
16 }
17 }).start();
18
19 new Thread(new Runnable() {
20 @Override
21 public void run() {
22 booleanThreadLocal.set(null);
23 integerThreadLocal.set(2);
24 Log.i(TAG, "testThreadLocal: b thread, boolean="+booleanThreadLocal.get());
25 Log.i(TAG, "testThreadLocal: b thread, int = "+integerThreadLocal.get());
26 }
27 }).start();
结果:
12020-01-08 10:15:38.623 8976-8976/com.hfy.demo01 I/hfy: testThreadLocal: main thread, boolean= true
22020-01-08 10:15:38.623 8976-8976/com.hfy.demo01 I/hfy: testThreadLocal: main thread, int = 0
32020-01-08 10:15:38.624 8976-9226/com.hfy.demo01 I/hfy: testThreadLocal: a thread, boolean=false
42020-01-08 10:15:38.624 8976-9226/com.hfy.demo01 I/hfy: testThreadLocal: a thread, int = 1
52020-01-08 10:15:38.626 8976-9227/com.hfy.demo01 I/hfy: testThreadLocal: b thread, boolean=null
62020-01-08 10:15:38.626 8976-9227/com.hfy.demo01 I/hfy: testThreadLocal: b thread, int = 2
到目前为止我们知道,ThreadLocal的作用,就是操作线程内部的threadLocals,存和取value。value的实际类型就是 实例化ThreadLocal时定义的泛型T。
2.2 messageQueue
messageQueue,消息队列,实际是单向链表。看下存、取消息。
enqueueMessage(),存消息,单链表的插入。
1 boolean enqueueMessage(Message msg, long when) {
2 if (msg.target == null) {
3 throw new IllegalArgumentException("Message must have a target.");
4 }
5 if (msg.isInUse()) {
6 throw new IllegalStateException(msg + " This message is already in use.");
7 }
8
9 synchronized (this) {
10 if (mQuitting) {
11 IllegalStateException e = new IllegalStateException(
12 msg.target + " sending message to a Handler on a dead thread");
13 Log.w(TAG, e.getMessage(), e);
14 msg.recycle();
15 return false;
16 }
17
18 msg.markInUse();
19 msg.when = when;
20 Message p = mMessages;
21 boolean needWake;
22 if (p == null || when == 0 || when < p.when) {
23 // New head, wake up the event queue if blocked.
24 msg.next = p;
25 mMessages = msg;
26 needWake = mBlocked;
27 } else {
28 // Inserted within the middle of the queue. Usually we don't have to wake
29 // up the event queue unless there is a barrier at the head of the queue
30 // and the message is the earliest asynchronous message in the queue.
31 needWake = mBlocked && p.target == null && msg.isAsynchronous();
32 Message prev;
33 for (;;) {
34 prev = p;
35 p = p.next;
36 if (p == null || when < p.when) {
37 break;
38 }
39 if (needWake && p.isAsynchronous()) {
40 needWake = false;
41 }
42 }
43 msg.next = p; // invariant: p == prev.next
44 prev.next = msg;
45 }
46
47 // We can assume mPtr != 0 because mQuitting is false.
48 if (needWake) {
49 nativeWake(mPtr);
50 }
51 }
52 return true;
53 }
next():取一条消息,没有消息就无限循环,会阻塞。
1 Message next() {
2 //...
3 //有msg就return,没有消息就无限循环,会阻塞。如quit,return null。
4 for (;;) {
5 if (nextPollTimeoutMillis != 0) {
6 Binder.flushPendingCommands();
7 }
8
9 nativePollOnce(ptr, nextPollTimeoutMillis);
10
11 synchronized (this) {
12 // Try to retrieve the next message. Return if found.
13 final long now = SystemClock.uptimeMillis();
14 Message prevMsg = null;
15 Message msg = mMessages;
16 if (msg != null && msg.target == null) {
17 // Stalled by a barrier. Find the next asynchronous message in the queue.
18 do {
19 prevMsg = msg;
20 msg = msg.next;
21 } while (msg != null && !msg.isAsynchronous());
22 }
23 if (msg != null) {
24 if (now < msg.when) {
25 // Next message is not ready. Set a timeout to wake up when it is ready.
26 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
27 } else {
28 // Got a message.
29 mBlocked = false;
30 if (prevMsg != null) {
31 prevMsg.next = msg.next;
32 } else {
33 mMessages = msg.next;
34 }
35 msg.next = null;
36 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
37 msg.markInUse();
38 //有消息就return
39 return msg;
40 }
41 } else {
42 // No more messages.
43 nextPollTimeoutMillis = -1;
44 }
45
46 // Process the quit message now that all pending messages have been handled.
47 if (mQuitting) {
48 dispose();
49 //quit后返回null
50 return null;
51 }
52
53 // ...
54 }
2.3 Looper
looper,消息循环器。
先看静态方法prepare():
1 // sThreadLocal.get() will return null unless you've called prepare().
2 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
3
4 /** Initialize the current thread as a looper.
5 * This gives you a chance to create handlers that then reference
6 * this looper, before actually starting the loop. Be sure to call
7 * {@link #loop()} after calling this method, and end it by calling
8 * {@link #quit()}.
9 */
10 public static void prepare() {
11 prepare(true);
12 }
13
14 private static void prepare(boolean quitAllowed) {
15 if (sThreadLocal.get() != null) {
16 throw new RuntimeException("Only one Looper may be created per thread");
17 }
18 sThreadLocal.set(new Looper(quitAllowed));
19 }
20
21 /**
22 * Initialize the current thread as a looper, marking it as an
23 * application's main looper. The main looper for your application
24 * is created by the Android environment, so you should never need
25 * to call this function yourself. See also: {@link #prepare()}
26 */
27 public static void prepareMainLooper() {
28 prepare(false);
29 synchronized (Looper.class) {
30 if (sMainLooper != null) {
31 throw new IllegalStateException("The main Looper has already been prepared.");
32 }
33 sMainLooper = myLooper();
34 }
35 }
36
37 private Looper(boolean quitAllowed) {
38 mQueue = new MessageQueue(quitAllowed);
39 mThread = Thread.currentThread();
40 }
可见sThreadLocal是个静态常量,value类型是Looper。
prepare()方法调sThreadLocal.set(new Looper),创建looper实例,设置给当前线程ThreadLocalMap属性中的table[i](i是threadLocal实例的hashCode相关)。
且创建looper实例时默认创建了对应的消息队列mQueue实例。另外,prepareMainLooper()是主线程,是给主线程创建looper实例。
再看下获取looper实例、queue实例的方法:
1 /**
2 * Returns the application's main looper, which lives in the main thread of the application.
3 */
4 public static Looper getMainLooper() {
5 synchronized (Looper.class) {
6 return sMainLooper;
7 }
8 }
9
10 /**
11 * Return the Looper object associated with the current thread. Returns
12 * null if the calling thread is not associated with a Looper.
13 */
14 public static @Nullable Looper myLooper() {
15 return sThreadLocal.get();
16 }
17
18 /**
19 * Return the {@link MessageQueue} object associated with the current
20 * thread. This must be called from a thread running a Looper, or a
21 * NullPointerException will be thrown.
22 */
23 public static @NonNull MessageQueue myQueue() {
24 return myLooper().mQueue;
25 }
myLooper() 方法,调用sThreadLocal.get()。就是上面讲解的ThreadLocal的使用方法。通过静态常量sThreadLocal获取对应每个线程的Looper实例。
looper的quit,两种,立即退出,执行完消息再退出。
1 /**
2 * Quits the looper.
3 * <p>
4 * Causes the {@link #loop} method to terminate without processing any
5 * more messages in the message queue.
6 * </p><p>
7 * Any attempt to post messages to the queue after the looper is asked to quit will fail.
8 * For example, the {@link Handler#sendMessage(Message)} method will return false.
9 * </p><p class="note">
10 * Using this method may be unsafe because some messages may not be delivered
11 * before the looper terminates. Consider using {@link #quitSafely} instead to ensure
12 * that all pending work is completed in an orderly manner.
13 * </p>
14 *
15 * @see #quitSafely
16 */
17 public void quit() {
18 mQueue.quit(false);
19 }
20
21 /**
22 * Quits the looper safely.
23 * <p>
24 * Causes the {@link #loop} method to terminate as soon as all remaining messages
25 * in the message queue that are already due to be delivered have been handled.
26 * However pending delayed messages with due times in the future will not be
27 * delivered before the loop terminates.
28 * </p><p>
29 * Any attempt to post messages to the queue after the looper is asked to quit will fail.
30 * For example, the {@link Handler#sendMessage(Message)} method will return false.
31 * </p>
32 */
33 public void quitSafely() {
34 mQueue.quit(true);
35 }
静态方法loop():用threadLocal.get()获取当前线程的Looper,然后拿到queue,循环取消息,给到handler的dispatchMessage方法-handleMessage方法。唯一跳出循环是取到null,null是因为调用了quit或quitSafly。
因为静态方法loop()是在线程中调用的,所以不论handler从哪里发送msg都会在loop的线程中执行。
1 /**
2 * Run the message queue in this thread. Be sure to call
3 * {@link #quit()} to end the loop.
4 */
5 public static void loop() {
6 final Looper me = myLooper();
7 if (me == null) {
8 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
9 }
10 final MessageQueue queue = me.mQueue;
11
12 // ...
13
14 for (;;) {
15 //没有msg ,queue.next()阻塞,loop() 也就阻塞了。next有msg就处理,无限循环。
16 Message msg = queue.next(); // might block
17 if (msg == null) {
18 //调用quit()时才会 跳出循环
19 // No message indicates that the message queue is quitting.
20 return;
21 }
22
23 // ...
24 //用target(handler)处理消息,dispatchMessage执行在loop() 调用的地方,即looper所在线程。
25 try {
26 msg.target.dispatchMessage(msg);
27 dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
28 } finally {
29 if (traceTag != 0) {
30 Trace.traceEnd(traceTag);
31 }
32 }
33 ...
34 }
35 }
流程 prepare()-new hanler()- loop() 连续的在同个线程调用。保证handleMessage执行在当前线程。即使handler.sengMessage()在其他线程调用。
2.4 Handler
发送,处理消息。
先看Handler构造方法,可见调用了Looper.myLooper(),就是获取当前线程的looper,没有就会抛出异常。
1 /**
2 * Default constructor associates this handler with the {@link Looper} for the
3 * current thread.
4 *
5 * If this thread does not have a looper, this handler won't be able to receive messages
6 * so an exception is thrown.
7 */
8 public Handler() {
9 this(null, false);
10 }
11
12 public Handler(Callback callback) {
13 this(callback, false);
14 }
15
16 public Handler(Callback callback, boolean async) {
17 ...
18 mLooper = Looper.myLooper();
19 if (mLooper == null) {
20 throw new RuntimeException(
21 "Can't create handler inside thread " + Thread.currentThread()
22 + " that has not called Looper.prepare()");
23 }
24 mQueue = mLooper.mQueue;
25 mCallback = callback;
26 mAsynchronous = async;
27 }
发送消息,就是把消息放入队列
1 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
2 msg.target = this;
3 if (mAsynchronous) {
4 msg.setAsynchronous(true);
5 }
6 return queue.enqueueMessage(msg, uptimeMillis);
7 }
处理消息,根据Handler的创建形式和使用方法对应处理。
1 /**
2 * Handle system messages here.
3 */
4 public void dispatchMessage(Message msg) {
5 if (msg.callback != null) {
6 //msg.callback就是handler.post()发送的runable
7 handleCallback(msg);
8 } else {
9 if (mCallback != null) {
10 //mCallback是创建Handler时传入CallBack的情况。
11 if (mCallback.handleMessage(msg)) {
12 return;
13 }
14 }
15 //覆写handleMessage()创建handler的情况
16 handleMessage(msg);
17 }
18 }
三、主线程的消息机制
主线程的消息
Looper中:
1 /**
2 * Initialize the current thread as a looper, marking it as an
3 * application's main looper. The main looper for your application
4 * is created by the Android environment, so you should never need
5 * to call this function yourself. See also: {@link #prepare()}
6 */
7 public static void prepareMainLooper() {
8 prepare(false);
9 synchronized (Looper.class) {
10 if (sMainLooper != null) {
11 throw new IllegalStateException("The main Looper has already been prepared.");
12 }
13 sMainLooper = myLooper();
14 }
15 }
ActivityThread的静态方法main:
1 final H mH = new H();
2
3 public static void main(String[] args) {
4 ...
5 //1、准备主线程的Looper
6 Looper.prepareMainLooper();
7
8 // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
9 // It will be in the format "seq=114"
10 long startSeq = 0;
11 if (args != null) {
12 for (int i = args.length - 1; i >= 0; --i) {
13 if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
14 startSeq = Long.parseLong(
15 args[i].substring(PROC_START_SEQ_IDENT.length()));
16 }
17 }
18 }
19 //这里实例化ActivityThread,也就实例化了上面的mH,就是handler。
20 ActivityThread thread = new ActivityThread();
21 thread.attach(false, startSeq);
22
23 //获取handler
24 if (sMainThreadHandler == null) {
25 sMainThreadHandler = thread.getHandler();
26 }
27
28 ...
29 //主线程looper开启
30 Looper.loop();
31 //因为主线程的Looper是不能退出的,退出就无法接受事件了。一旦意外退出,会抛出异常
32 throw new RuntimeException("Main thread loop unexpectedly exited");
33 }
H处理了四大组件的启动停止等。ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS完成ActivityThread的请求后,回调到ApplicationThread中的binder方法,然后ApplicationThread使用H发送消息,然后就把此消息切换到ApplicationThread中执行,即在主线程执行。 这就是主线程的消息循环。