Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4062e89

Browse files
author
ubuntulover
committed
add android analysis
1 parent 47892fa commit 4062e89

File tree

5 files changed

+417
-253
lines changed

5 files changed

+417
-253
lines changed

Android/LooperHandler.md

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
### Handler, Looper, Message Queue, Runnable源码分析
2+
3+
大家做Android开发难免不和这几个哥们打交道。而且基本上,面试必问。为了学习,也为了搞清楚这个东西,我决定从源码的角度分析这几个哥们。
4+
5+
首先说一下关系:
6+
7+
- `Runnable``Message`可以放入某个`MessageQueue`里面,形成一个集合
8+
- `Looper`循环的从`Message Queue`里面取出一个东西,交由`Handler`进行处理
9+
- `Handler`才是真正干活的地方
10+
11+
12+
13+
14+
15+
既然`Handler`才是干活的,我们来先看看这个哥们长啥样子。
16+
17+
源码代码位置:`$ANDROID_BASE/frameworks/base/core/android/os/Handler.java`
18+
19+
`$ANDROID_BASE/frameworks/base/core/android/os/Looper.java`
20+
21+
`$ANDROID_BASE/frameworks/base/core/android/os/MessageQueue.java`
22+
23+
`Handler.java`
24+
25+
```java
26+
public class Handler {
27+
...
28+
29+
final Looper mLooper;
30+
final MessageQueue mQueue;
31+
final Callback mCallback;
32+
}
33+
```
34+
35+
`Looper.java`
36+
37+
```java
38+
public final class Looper { // 注意这里的final 关键字
39+
...
40+
// sThreadLocal.get() will return null unless you've called prepare().
41+
@UnsupportedAppUsage
42+
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
43+
@UnsupportedAppUsage
44+
private static Looper sMainLooper; // guarded by Looper.class
45+
private static Observer sObserver;
46+
47+
@UnsupportedAppUsage
48+
final MessageQueue mQueue;
49+
final Thread mThread;
50+
51+
}
52+
```
53+
54+
`MessageQueue.java`
55+
56+
```java
57+
public final class MessageQueue {
58+
...
59+
Message message;
60+
}
61+
```
62+
63+
64+
65+
可以发现:
66+
67+
1. 一个线程,只有一个Looper
68+
2. 一个Looper,只有一个MessageQueue
69+
3. 一个MessageQueue有多个Message
70+
4. 一个Message最多指定一个Handler来处理。
71+
72+
继续看源码,我们可以发现`Handler`主要这么两个职责:
73+
74+
- 处理`Message`
75+
- 将某个`Message`发送出去(放到MessageQueue中)
76+
77+
来看看`Looper`取出消息分发的相关代码:
78+
79+
```java
80+
public static void loop() {
81+
final Looper me = myLooper();
82+
if (me == null) {
83+
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
84+
}
85+
final MessageQueue queue = me.mQueue;
86+
87+
// Make sure the identity of this thread is that of the local process,
88+
// and keep track of what that identity token actually is.
89+
Binder.clearCallingIdentity();
90+
final long ident = Binder.clearCallingIdentity();
91+
// 此处死循环来从队列里面取消息
92+
for (;;) {
93+
Message msg = queue.next(); // might block
94+
if (msg == null) {
95+
// No message indicates that the message queue is quitting.
96+
// 如果是空,说明正在退出
97+
return;
98+
}
99+
100+
// This must be in a local variable, in case a UI event sets the logger
101+
final Printer logging = me.mLogging;
102+
if (logging != null) {
103+
logging.println(">>>>> Dispatching to " + msg.target + " " +
104+
msg.callback + ": " + msg.what);
105+
}
106+
// Make sure the observer won't change while processing a transaction.
107+
final Observer observer = sObserver;
108+
109+
final long traceTag = me.mTraceTag;
110+
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
111+
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
112+
if (thresholdOverride > 0) {
113+
slowDispatchThresholdMs = thresholdOverride;
114+
slowDeliveryThresholdMs = thresholdOverride;
115+
}
116+
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
117+
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
118+
119+
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
120+
final boolean needEndTime = logSlowDispatch;
121+
122+
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
123+
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
124+
}
125+
126+
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
127+
final long dispatchEnd;
128+
Object token = null;
129+
if (observer != null) {
130+
token = observer.messageDispatchStarting();
131+
}
132+
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
133+
try {
134+
// 最关键的地方,这里就是调用message的handler来处理这个消息。
135+
msg.target.dispatchMessage(msg);
136+
if (observer != null) {
137+
observer.messageDispatched(token, msg);
138+
}
139+
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
140+
} catch (Exception exception) {
141+
if (observer != null) {
142+
observer.dispatchingThrewException(token, msg, exception);
143+
}
144+
throw exception;
145+
} finally {
146+
ThreadLocalWorkSource.restore(origWorkSource);
147+
if (traceTag != 0) {
148+
Trace.traceEnd(traceTag);
149+
}
150+
}
151+
152+
153+
// Make sure that during the course of dispatching the
154+
// identity of the thread wasn't corrupted.
155+
final long newIdent = Binder.clearCallingIdentity();
156+
if (ident != newIdent) {
157+
Log.wtf(TAG, "Thread identity changed from 0x"
158+
+ Long.toHexString(ident) + " to 0x"
159+
+ Long.toHexString(newIdent) + " while dispatching to "
160+
+ msg.target.getClass().getName() + " "
161+
+ msg.callback + " what=" + msg.what);
162+
}
163+
164+
msg.recycleUnchecked();
165+
}
166+
}
167+
```
168+
169+
OK, 了解到了Looper会把Message分给Handler来做,那么来继续看Handler里面的`dispatchMessage(Message)`这个方法。
170+
171+
```java
172+
public void dispatchMessage(@NonNull Message msg) {
173+
if (msg.callback != null) {
174+
handleCallback(msg);
175+
} else {
176+
if (mCallback != null) {
177+
if (mCallback.handleMessage(msg)) {
178+
return;
179+
}
180+
}
181+
handleMessage(msg);
182+
}
183+
}
184+
```
185+
186+
可以看到,这里的分发策略是:
187+
188+
:arrow_right:`Message.Callback`对象是否为空
189+
190+
​ 在不为空的情况下,交由这个callback来处理,因此优先级较高
191+
192+
:arrow_right:`Handler.mCallback`
193+
194+
​ 在不为空的情况下,交由这个callback来处理,优先级其次
195+
196+
:arrow_right:`handleMessage(Message)`
197+
198+
​ 当上述条件都不满足的时候,调用它来处理。(通常,如果我们写一个子类来继承`Handler`类的话,你是需要重载这个方法的)
199+
200+
所以,`Handler`的扩展子类可以重载`dispatchMessage(Message)`这个方法,或者直接重载`handleMessage(message)`这个方法。具体情况,应该根据项目实际需求来走。
201+
202+
203+
204+
---
205+
206+
207+
208+
#### 进一步分析
209+
210+
看完上述代码之后,`Handler`这个哥们可能会让你疑惑,会有这么一个循环:
211+
212+
`Handler`:arrow_right:`MessageQueue`:arrow_right:`Message`:arrow_right:`Handler`
213+
214+
即:
215+
216+
1. `Handler`把消息放到`MessageQueue`
217+
2. `MessageQueue``Message``Handler`
218+
219+
首先我们来看看`Handler`有哪些发消息的方法:
220+
221+
```java
222+
// post系列
223+
public final boolean post(@NonNull Runnable r);
224+
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis);
225+
public final boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis);
226+
public final boolean postDelayed(@NonNull Runnable r, long delayMillis);
227+
public final boolean postDelayed(@NonNull Runnable r, int what, long delayMillis);
228+
public final boolean postDelayed(@NonNull Runnable r, Object token, long delayMillis);
229+
public final boolean postAtFrontOfQueue(@NonNull Runnable r);
230+
231+
// send系列
232+
public final boolean sendMessage(@NonNull Message msg);
233+
public final boolean sendEmptyMessage(int what);
234+
public final boolean sendEmptyMessageDelayed(int what, long delayMillis);
235+
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis);
236+
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis);
237+
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis);
238+
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg);
239+
240+
```
241+
242+
这两个系列的方法都可以把`Message`放到`MessageQueue`中。不同的是,send系列参数都直接是`Message`, 而post系列参数都是`Runnable`,因此多了一步中间转换过程,然后再调用send系列的函数进行入队。
243+
244+
我们挑一个最简单的post系列函数,来分析一下源码:
245+
246+
```java
247+
public final boolean post(Runnable r) {
248+
return sendMessageDelayed(getPostMessage(r), 0);
249+
}
250+
```
251+
252+
可以发现,这里调用了一个函数`getPostMessage(Runnable)`来封装出一个`Message`,接着调用send系列的函数来入队:
253+
254+
```java
255+
private static Message getPostMessage(Runnable r) {
256+
Message m = Message.obtain(); // 1
257+
m.callback = r; // 2
258+
return m;
259+
}
260+
```
261+
262+
在代码1处,Android会维护一个全局的Message池,当用户需要使用Message的时候,可以直接通过obtain方法获得。这样的设计是避免不必要的资源浪费。
263+
264+
代码2处的直接把当前的runnable对象设置成回调函数。
265+
266+
当准备好Message之后,系统就会调用`sendMessageDelayed`方法来发送消息。这个函数可以设定多长时间的延迟再发送消息,内部的处理是通过当前时间+延迟时间算出该在哪个时间点发送(`sendMessageAtTime)`
267+
268+
```java
269+
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
270+
if (delayMillis < 0) {
271+
delayMillis = 0;
272+
}
273+
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
274+
}
275+
```
276+
277+
```java
278+
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
279+
MessageQueue queue = mQueue;
280+
if (queue == null) {
281+
RuntimeException e = new RuntimeException(
282+
this + " sendMessageAtTime() called with no mQueue");
283+
Log.w("Looper", e.getMessage(), e);
284+
return false;
285+
}
286+
return enqueueMessage(queue, msg, uptimeMillis); // 这里就是入队
287+
}
288+
```
289+
290+
看到这里,我们会有一个疑问,为什么要大费周章,先把`Message` 放到`MessageQueue`里面,最后还是由`Handler`来处理呢?
291+
292+
293+
294+
---
295+
296+
#### 继续分析
297+
298+
上面设计哲学个人认为是有序性。
299+
300+
当你在主线程发送一个计算量特别大的任务的时候,如果你马上来处理这个任务,主线程就卡死了。那么交由子线程来计算,当它计算好了之后,发个消息告诉主线程,可以了。这样既不会影响主线程的交互(通常把UI线程称为主线程),计算任务又得以进行。
301+
302+
#### MessageQueue分析
303+
304+
MessageQueue的分析可能需要你具有一定的JNI知识。因此这里不会过多深入的分析。
305+
306+
简单看看源码,它有这么一些操作:
307+
308+
- 新建队列
309+
310+
由一个本地方法(native方法)`nativeInit()`来创建完成,这个函数返回一个`long`类型的值。这个操作由指针操作完成,具体分析JNI的时候可以再回头看。
311+
312+
- 元素入队
313+
314+
`boolean enqueueMessage(Message msg, long when)`
315+
316+
- 元素出队
317+
318+
`Message next()`
319+
320+
- 删除元素
321+
322+
`void removeMessages(Handler h, int what, Object obj)`
323+
324+
`void removeMessages(Handler h, Runnable r, Object obj)`
325+
326+
- 销毁队列
327+
328+
销毁队列也是一个本地方法完成的,`nativeDestroy()`。实质上,这个东西根所学的队列没有本质区别,因此不做过多赘述,有相关的需求可以回顾数据结构。
329+
330+
331+
332+
#### Looper分析
333+
334+
这个哥们比较有意思了。Looper有点像发动机的意思--它才会推动消息的处理。
335+
336+
应用程序使用Looper分两种情况,
337+
338+
:arrow_right_hook:主线程(MainThread,也是AcitivtyThread)
339+
340+
:arrow_right_hook:普通线程
341+
342+
我们看一下普通线程的用法:
343+
344+
```java
345+
class MyLooperThread extends Thread {
346+
public Handler mhandler; // 谁干活?
347+
348+
@Override
349+
public void run() {
350+
Looper.prepare(); // 1
351+
mHandler = new Handler() {
352+
public void handleMessage() {
353+
// 这里就是前文中处理消息的地方!!!
354+
}
355+
};
356+
Looper.loop(); // 2
357+
}
358+
}
359+
```
360+
361+
我们发现这里有三个步骤:
362+
363+
1. 调用Looper的`prepare()`方法;
364+
2. 创建Handler;
365+
3. Looper开始运作;
366+
367+
可以看到,我们没有发现有Looper对象的创建,最后也是一句Looper.loop,整个消息循环系统就跑起来了。
368+
369+
370+
371+
372+

Android/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44

55
关于如何获取编译代码的方法网络上烂大街。具体操作请参考他们。有没有梯子都可以。
66

7-
[Android一些同步机制的分析](Android/sync.md)
7+
[Android一些同步机制的分析](Android/sync.md)
8+
9+
[Android中Looper,Handler,MessageQueue的分析](Android/LooperHandler.md)

0 commit comments

Comments
 (0)