简介

很多人面试肯定都被问到过,请问Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论。

Handler 、 Looper 、Message 这三者都与Android异步消息处理线程相关的概念。那么什么叫异步消息处理线程呢?

异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。说了这一堆,那么和Handler、Looper、Message有啥关系?其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。

所以,下面我们依次讲解一下这几个东西。看他们到底是个什么鬼?

Looper对象源码

首先,我们来看Looper对象,对于Looper主要是prepare()和loop()两个方法。

首先,我们看一下Looper的prepare方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 就是这个地方调用的prepare(true);也就是默认允
* 许quit
*/
public static void prepare() {
prepare(true);
}
//我们分析prepare的方法
private static void prepare(boolean quitAllowed) {
// 首先通过sThreadLocal来查看当前线程是否有lopper对象
// 原则上一个线程内只有一个lopper对象。也允许调用一次prepare方法。所以多次调用会报错
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 正常情况下,将Lopper对象存储到sThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}

参考代码中重点1:
sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。可以看到,在第5行,将一个Looper的实例放入了ThreadLocal,并且2-4行判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例。

接着,下面我们在分析一下Looper的构造函数

1
2
3
4
5
6
7
// 重点2:我们来看Lopper的构造函数
private Looper(boolean quitAllowed) {
// Lopper其实就是创建了一个MessageQueue。也就是一个消息队列对象
mQueue = new MessageQueue(quitAllowed);
// 获取当前的线程,是不是很简单
mThread = Thread.currentThread();
}

构造方法中,创建了一个MessageQueue(消息队列)。并且获取当前的Thread对象。这里的逻辑还是比较简单的,下一位Looper对象就开始不停的遍历这个MessageQueue了。那么他是怎么遍历的呢?对,就是通过Loop方法。

最后,我们再看看loop的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  /**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
* 这个方法主要是进行当前线程里面的message queue队列的遍历,来遍历消息,进行消息的分发
*/
public static void loop() {
// 这个方法就是从TreadLocal里面取得当前的Looper对象。
// 也就是我们每个线程实例化的ThreadLocal对象
final Looper me = myLooper();
// 毫无疑问,me为null 表示这个线程里面没有进行Looper对象的Looper.prepare()初始化。
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 这个queue就是构造函数中实例化的mQueue
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();

// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);

boolean slowDeliveryDetected = false;
// Looper的loop方法执行死循环。
// 我们可以看到这个地方,是执行了一个死循环,在这个死循环中依次遍历queue里面的所有消息
for (;;) {
// 从Looper的queue中依次取出消息实体
// 拿到下一个Message.如果没有消息这个地方就会阻塞掉
Message msg = queue.next(); // might block

// 如果为null,表明这个额消息队列正在停止,这个时候就跳出循环。
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);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;

final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;

if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}

final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
// 我们从这个地方调用 msg.target的dispatchMessage()方法
// 那么 msg.target对象是什么?
// 其实就是Handler对象
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}

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主要作用:

1、 调用prepare()来进行初始化。保证一个线程只会有一个Looper实例,构造一个MessageQueue对象。获取当前线程进行绑定。

2、 调用loop()方法,进入无限循环中不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。这样就达到了不断处理当前的线程消息的功能。

但是,到这个地方,我们思考一个问题:

要达到处理消息的效果。必然有地方进行Looper.prepare()的初始化。并且调用loop()方法才对呀!!!

我们知道,我们在Activity里面或者其他地方来使用Handler的时候并没有调用Looper.prepare()啊。

所以就引出我们下面进行讲解的:主线程的异步消息机制是怎么启动的??

ActivityUI线程的异步消息机制的启动

一个Android程序总要有自己的入口Main()函数吧??没错就是android.app.ActivityThread这个类中的main(),下面我们分析一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* Android程序的启动入口函数
*/
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

// Install selective syscall interception
AndroidOs.install();

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

// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);

Process.setArgV0("<pre-initialized>");
// 初始化主线程功能的Looper
// 步骤一:Looper.prepareMainLooper()初始化主线程(UI)的Lopper对象
Looper.prepareMainLooper();

// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 实例化ActivityThread的对象
// 这个地方就是实例化ActivityThread
ActivityThread thread = new ActivityThread();
//
thread.attach(false, startSeq);
// 获取主线程的Handler对象
// 步骤二:同时在这个主线程获取sMainThreadHandler
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方法,开始执行消息的循环
//步骤三: 调用Main主线程里面的loop方法
Looper.loop();

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

通过Android程序启动之后,就在这个地方开始执行MessageQueue的遍历方法。

好了,我们的异步消息处理线程已经有了消息队列(MessageQueue),也有了在无限循环体中取出消息的哥们,现在缺的就是发送消息的对象了,于是乎:Handler登场了。