Android 性能专题 - 启动优化(一)启动耗时

声明:本文是《Android 性能优化入门与实战》——张世欣著 的笔记

为什么要做启动优化

App 启动耗时每减少 1s,用户流失率降低 6.9%

启动监控

1
2
3
4
5
6
7
8
9
补充知识

**App 冷温热启动分辨**:根据进程、Activity 是否已经存在

**冷启动**: 进程初始化 -> Activity.onCreate -> Activity.onStart

**温启动**: Activity.onCreate -> Activity.onStart

**热启动**:Activity.onStart

监控数据设计

需要比较的对照组:

  1. 旧版本-新版本
  2. 冷启动-温启动-热启动

数据与目的:

  1. 获取总耗时,判断新版本更快还是更慢
  2. 获取各区间耗时,具体分析耗时到具体区间

App 启动代码顺序

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
Application 构造函数

Application#attachBaseContext

ContentProvider#onCreate

Application#onCreate

Activity#onStart

Activity#onResume

View#onDraw

Activity#onWindowFocusChanged

起点:Application 构造函数

终点:

方案一:MainActivity 的某个 View 的第一次 onDraw(绘制函数)

- 优点:可以拿到第一帧绘制的耗时
- 缺点:
1. 执行时第一帧还没绘制完成
2. 需要选择某个核心布局,业务改造的时候容易影响到启动监控逻辑

方案二:MainActivity 的 onWindowFocusChanged

- 优点:不受业务逻辑的影响
- 缺点:被调用的时可能已经不是首帧,会将非首帧的时间算入

获取启动各阶段耗时

方法:

  1. 手动埋点
  2. 编译时 AOP

获取启动性能数据

1
2
3
4
5
6
分析 App 启动慢的几个重要指标
-> 代码耗时 (判断标准:App 运行的 CPU 时间充足)
-> 获取的 CPU 时间不足 (判断标准:App 运行的 CPU 时间不足)
-> 线程优先级不够 (判断标准:主线程优先级)
-> 被其他线程抢占过多 (判断标准:主线程被抢占次数)
-> 内存不足 (判断标准:启动期间 GC 执行次数和耗时)

线下分析

Logcat 或者 adb logcat 中查看关键字 Displayed 相关日志

自动执行 App的启动并获取启动耗时:通过 adb shell am start 实现多次自动启动 App 并获取第一次的启动耗时:

1
adb shell am start -S -W -R -3 com.antfortune.wealth/com.alipay.mobile.quinox.LauncherActivity
  • am start 是 ActivityManagerService 提供的命令,用来启动 Activity。
  • - S 即 Stop,表示在每次启动前,先强制停止 App 运行,以实现冷启动。
  • - W 即 Wait,表示执行后等待启动完成再退出,以统计整个启动的耗时。
  • - R 即 Repeat, 表示重复执行启动的次数,-R 3 表示重复启动 3 次。

会得到以下信息

1
2
3
4
5
6
7
8
Stopping: com.antfortune.wealth
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.antfortune.wealth/com.alipay.mobile.quinox.LauncherActivity }
Status: ok
LaunchState: COLD
Activity: com.antfortune.wealth/com.alipay.mobile.quinox.LauncherActivity
TotalTime: 463
WaitTime: 467
Complete

上述 TotalTime 就是整个冷启动的耗时,与 Locat 过滤 Displayed 得到的时间基本是一致的。

这两种方式,统计的都是 App 启动到 Activity 首次调用的时间 onWindowFocusChanged 的时间

如果想统计从 App 启动到数据请求成功后某个布局完全展示出来的耗时,可以在启动终点调用 Activity#reportFullyDrawn 来通知当前

已经完全绘制完成,然后在 Logcat 里过滤 Fully drawn 就可以看到整个流程的耗时。

Android Framework 专项 - Handler(一)

问题

1
2
The formulation of the problem is often more essential than its solution, which may be merely a matter of mathematical or experimental skill.
― Albert Einstein

Q:一个线程有几个 Handler?

Q: 线程间的通信的原理是怎样的?

Q: Handler 内存泄漏的原因?为什么其他的内部类没有说过这个问题?

Q: 为何主线程可以 new Handler ?如果想要在子线程中 new Handler 要做些什么准备?

Q: 子线程中维护的 Looper,消息队列无消息的时候的处理方案是什么?有什么用?

Q: 既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个 Handler 可能处于不同线程),那它内部时如何确保线程安全的?

Q: Looper 死循环为什么不会导致应用卡死

Q: 为什么主线程不需要自己创建和管理消息循环

Handler 在 Android 中的应用

1
Handler 是针对 Android 系统中与 UI 线程通信而专门设计的多线程通信机制

Retorfit,eventbus,rxjava,Looper

Handler 源代码分析

子线程 发送 MSG

​ android.os.Handler#sendMessage ->
​ android.os.Handler#sendMessageDelayed ->
​ android.os.Handler#sendMessageAtTime ->
​ android.os.Handler#enqueueMessage ->
​ android.os.MessageQueue#enqueueMessage ->
​ android.os.Looper#loop

android.os.Handler#sendMessage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    /**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
/**
* 在所有挂起的消息之后将消息推送到消息队列的末尾
* 当前时间之前。它将在 {@link #handleMessage} 中收到,
* 在附加到该处理程序的线程中。
*
* @return 如果消息成功放入则返回 true
* 消息队列。失败时返回 false,通常是因为
* 处理消息队列的 looper 正在退出。
*/
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
android.os.Handler#sendMessageDelayed
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
/**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
/**
* 将一条消息放入消息队列中,位于所有挂起的消息之后
* 之前(当前时间+delayMillis)。您将在以下时间收到它:
* {@link #handleMessage},在附加到该处理程序的线程中。
*
* @return 如果消息成功放入则返回 true
* 消息队列。失败时返回 false,通常是因为
* 处理消息队列的 looper 正在退出。请注意,一个
* true 的结果并不意味着该消息将被处理 -- 如果
* Looper 在消息发送之前退出
* 发生则消息将被丢弃。
*/
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
android.os.Handler#sendMessageAtTime
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
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
/**
* 将消息排队到消息队列中,在绝对时间(以毫秒为单位)<var>uptimeMillis</var>之后的所有挂起消息之后。
* <b>时间基准是 {@link android.os.SystemClock#uptimeMillis}。</b>
* 在深度睡眠期间花费的时间将会额外延迟执行。
* 您将在{@link #handleMessage}中接收它,该方法会在与此处理程序连接的线程中执行。
*
* @param uptimeMillis 消息应该传递的绝对时间,使用{@link android.os.SystemClock#uptimeMillis}作为时间基准。
*
* @return 如果消息成功放置到消息队列中,则返回 true 。如果失败,则返回 false ,通常是因为处理消息队列的消息循环正在退出。
* 请注意,返回true并不意味着消息将被处理 - 如果消息传递时间之前消息循环被退出,则消息将被丢弃。
*/
public boolean sendMessageAtTime(@NonNull 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);
}
android.os.Handler#enqueueMessage
1
2
3
4
5
6
7
8
9
10
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();

if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

到这里,发送流程都没什么好说的

重点:android.os.Handler#handleMessage
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
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}

synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}

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;
}
msg.target 是什么

注意:这里 msg.target 就是 msg 持有的 handler 也是 为什么会有内存泄漏风险的原因。

分析代码:

Handler 内存泄漏原因

Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler持有,这样最终就导致 Activity 泄露。

它的主要作用是将消息按照时间顺序插入到消息队列中,并在必要时唤醒队列以处理这些消息。下面逐步分析代码的功能和逻辑。

  1. 首先,代码对传入的消息 msg 进行一些验证。它确保消息有一个非空的目标(msg.target != null),否则抛出 IllegalArgumentException

  2. 然后,代码在同步块内执行以下操作:

    • 检查消息是否已经在使用中,如果是,则抛出 IllegalStateException。这可能是为了防止重复使用消息,确保每个消息只被处理一次。

    • 检查当前处理器是否正在退出(mQuitting 标志),如果是,就回收消息并返回 false,表示消息未被成功加入队列。

    • 将消息标记为正在使用,并设置消息的触发时间 msg.when 为传入的 when

    • 获取消息队列的头部消息 p

  3. 接下来,代码根据以下条件进行处理:

    • 如果消息队列为空,或者传入的触发时间 when 为 0,或者传入的 when 小于队列头部消息的触发时间 p.when,则将新消息插入到队列头部。如果队列当前被阻塞(mBlocked 标志),则设置需要唤醒队列(needWake = true)。

    • 否则,如果消息需要插入队列中间,则根据条件判断是否需要唤醒队列。具体判断条件是:队列被阻塞、队列头部消息的目标为 null,且传入的消息是异步消息。然后,代码在一个循环中遍历消息队列,找到合适的位置插入新消息。循环会一直迭代,直到找到合适的位置或者遍历完整个队列。

    • 在找到合适的位置后,代码将新消息 msg 插入到队列中。具体做法是,将 msg.next 设置为当前消息 p,然后将前一个消息 prev.next 设置为新消息 msg

  4. 最后,代码根据之前的标志 needWake 来决定是否唤醒队列。如果需要唤醒,则调用本地的 nativeWake 方法(可能是一个底层的本地方法)来唤醒消息队列。

  5. 整个同步块结束后,代码返回 true,表示消息已经成功加入队列。

这段代码的核心功能是在消息队列中插入消息并进行适当的排序,以确保消息按照触发时间顺序进行处理。同时,它还处理了一些异常情况,如消息已经在使用中或者处理器正在退出。唤醒队列的逻辑也在代码的最后部分进行处理。

让我们逐步分析 MSG 插入队列的位置:

第一种插入头部的情况:
1
2
3
4
5
6
7
8
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 {
...
}
  1. 如果消息队列为空,意味着当前没有任何消息在队列中等待处理。在这种情况下,不需要比较触发时间,直接将新消息插入到队列的头部。这会让新消息成为队列的第一个要处理的消息。
  2. 如果传入的触发时间 when 为 0,这可能表示该消息需要尽快处理,因此同样将它插入到队列的头部。
  3. 如果传入的触发时间 when 小于队列头部消息的触发时间 p.when,这意味着新消息应该在队列中位于当前头部消息之前,因此同样将它插入到队列的头部

综合上述情况,无论是队列为空,还是传入的 when 值为 0,或者传入的 when 值小于队列头部消息的触发时间,都会将新消息插入到队列的头部

第二种插入中间的情况:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if(p == null || when == 0 || when < p.when) {
...
} 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;
}
  1. 首先,如果不满足前面提到的条件(消息队列为空,传入的触发时间为0,或传入的触发时间小于队列头部消息的触发时间),那么意味着要插入的新消息 msg 应该位于队列中间。
  2. 在这种情况下,代码会进入一个循环。这个循环的目的是遍历消息队列,以找到合适的位置将新消息 msg 插入队列中。
  3. 循环的条件是 for (;;),这将创建一个无限循环,直到内部的某个条件满足而跳出循环。
  4. 在每次循环迭代中,代码会做以下事情:
    • 将当前消息 p 的引用赋值给 prev,这样可以记录下前一个消息。
    • p 移动到下一个消息(p = p.next)。
  5. 然后,代码检查两个条件:
    • 如果当前消息 p 为空,意味着已经遍历了整个队列,或者队列只有一个消息且当前消息是最后一个消息。
    • 如果传入的触发时间 when 小于队列中当前消息 p 的触发时间 p.when
  6. 如果满足以上任一条件,循环会被中断,这表示找到了合适的位置将新消息 msg 插入到消息队列中。
  7. 在循环的每个迭代中,代码还会检查以下条件:
    • 如果需要唤醒队列(needWake = true),并且当前消息 p 是异步消息(p.isAsynchronous() 返回 true),则将 needWake 设置为 false。这个步骤可能是为了控制是否需要在队列中插入异步消息时唤醒队列。
  8. 一旦找到了合适的位置,代码会执行以下操作:
    • 将新消息 msgnext 指针指向当前消息 p,这相当于将新消息插入到当前消息 p 之前。
    • 将前一个消息 prevnext 指针指向新消息 msg,以确保队列中消息的连接关系正确。
  9. 循环结束后,新消息 msg 已经被插入到队列的合适位置,保持了消息队列的有序性。

总之,这段代码的目的是在消息队列中将新消息插入到适当的位置,以保持消息的时间顺序。在找到合适位置时,会根据一些条件来决定是否需要唤醒队列,这可能与队列的处理机制相关。

此外,如果当前消息队列被阻塞(mBlocked 为 true),则将标志 needWake 设置为 true。这是为了确保在需要唤醒队列以处理消息的情况下,能够在适当的时候执行唤醒操作。唤醒队列的操作可能涉及到一些底层机制,具体如何唤醒可能需要查看更多上下文代码。

总的来说,这段代码逻辑的目的是在特定条件下将新消息插入到消息队列的头部,并根据当前队列的阻塞状态决定是否需要唤醒队列以确保消息能够被及时处理。

主线程 取出 MSG

​ android.os.Looper#loop ->
​ android.os.MessageQueue#next ->
​ android.os.Handler#dispatchMessage ->
​ android.os.Handler#handleMessage

主线程中的 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
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);

// Call per-process mainline module initialization.
initializeMainlineModules();

Process.setArgV0("<pre-initialized>");

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 thread = new ActivityThread();
thread.attach(false, startSeq);

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

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

与 handler 相关的关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
...

Looper.prepareMainLooper();
...

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
···

Looper.loop();

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

准备 Looper

1
Looper.prepareMainLooper();

android.os.Looper#prepareMainLooper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. See also: {@link #prepare()}
*
* @deprecated The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
*/
@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();
}
}

android.os.Looper#prepare(boolean)

1
2
3
4
5
6
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));
}

准备 Handler

1
2
3
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

android.app.ActivityThread#getHandler

1
2
3
4
@UnsupportedAppUsage
public Handler getHandler() {
return mH;
}

android.app.ActivityThread#mH

1
2
@UnsupportedAppUsage
final H mH = new H();

开启循环

1
Looper.loop();
重点:android.os.Looper#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
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}

me.mInLoop = true;

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

me.mSlowDeliveryDetected = false;

for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}

这段代码是 Android 框架中 Looper 类的 loop() 方法的实现,负责在当前线程的消息循环中执行消息的分发和处理。

  1. 首先,通过 myLooper() 获取当前线程的 Looper 实例 me,如果没有 Looper 实例则抛出异常,表示未调用 Looper.prepare() 来准备 Looper。
  2. 检查 me.mInLoop,如果当前线程已经在消息循环中,则打印警告日志。
  3. me.mInLoop 标志设置为 true,表示当前线程正在消息循环中。
  4. 使用 Binder.clearCallingIdentity() 来清除当前线程的调用标识,然后再次调用它并将返回的标识 ident 保存下来。
  5. 获取一个可能的系统属性覆盖值 thresholdOverride,用于调整慢分发的阈值。
  6. me.mSlowDeliveryDetected 设置为 false,用于标记是否检测到慢投递。
  7. 进入一个无限循环,不断地执行消息分发和处理。
  8. 在循环中,调用 loopOnce(me, ident, thresholdOverride) 来执行一次消息分发。如果返回值为 false,表示没有更多的消息需要分发,退出循环。

总之,这段代码描述了 Android 中消息循环的核心逻辑。它会在一个无限循环中,不断地从消息队列中获取消息并执行消息分发和处理,直到没有更多的消息需要处理为止。在循环中,还会检查是否有慢分发阈值的系统属性覆盖,并根据需要清除调用标识。如果发现当前线程已经在消息循环中,则会打印警告信息。

#loopOnce
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
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}

// 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 = needSt

从零开始写一个 ARouter - router-annotation 路由注解模块

  • ARouter
    • router-annotation 路由注解模块

    • arouter-api ARouter框架的API模块

      • src.main.java
        • com.alibaba.android.arouter
          • base 基础功能相关的包
            • UniqueKeyTreeMap.java 唯一键树形映射的类
          • core 核心功能相关的包
            • AutowiredLifecyleCallback.java(废弃) 自动注入生命周期回调的类
            • AutowiredServiceImpl.java 自动注入服务的实现类
            • InstrumentationHook.java(废弃) 仪表钩子的类
            • InterceptorServiceImpl.java 拦截器服务的实现类
            • LogisticsCenter.java 物流中心的类
            • Warehouse.java 仓库的类
          • exception 异常相关的包
            • HandlerException.java 处理异常的类
            • InitException.java 初始化异常的类
            • NoRouteFoundException.java 未找到路由的异常类
          • facade 提供各种服务和回调的包
            • callback 回调相关的包
              • InterceptorCallback.java 拦截器回调的接口
              • NavigationCallback.java 导航回调的接口
              • NoRouteFoundException.java 未找到路由的异常接口
          • service 服务相关的包
            • AutowiredService.java 自动注入服务的接口
            • ClassLoaderService.java 类加载器服务的接口
            • DegradeService.java 降级服务的接口
            • InterceptorService.java 拦截器服务的接口
            • PathReplaceService.java 路径替换服务的接口
            • PretreatmentService.java 预处理服务的接口
            • SerializationService.java 序列化服务的接口
          • template 模板相关的包
            • IInterceptor.java 拦截器接口
            • IInterceptorGroup.java 拦截器分组接口
            • Ilogger.java 日志记录器接口
            • IPolicy.java 策略接口
            • IProvider.java 提供者接口
            • IProviderGroup.java 提供者分组接口
            • IRouteGroup.java 路由分组接口
            • IRouteRoot.java 路由根接口
            • Isyringe.java 注射器接口
            • Postcard.java 路由信息封装类
          • launcher 启动器: 包含一些用于启动ARouter框架的类和线程管理相关的类。
            • _Arouter.java ARouter框架的内部启动类,用于初始化ARouter。
            • Arouter.java ARouter框架的启动类,用于初始化ARouter。
          • thread (线程)包含了与线程管理相关的类。
            • CancelableCountDownLatch.java 可取消的倒计时计数器,用于线程同步。
            • DefaultPoolExecutor.java 默认的线程池执行器,用于执行异步任务。
            • DefaultThreadFactory.java 默认线程工厂,用于创建线程。
          • utils 工具类。
            • ClassUtils.java 用于操作类的实用工具类。
            • Consts.java 包含一些常量值的类。
            • DefaultLogger.java 默认的日志记录器类。
            • MapUtils.java 用于操作地图数据的实用工具类。
            • PackageUtils.java 用于操作包信息的实用工具类。
            • TextUtils.java 用于操作文本数据的实用工具类。
    • arouter-compiler

      • src.main.java
        • com.alibaba.android.arouter
          • compiler 编译相关的包
            • entity 实体类相关的包
              • RouteDoc.java 路由文档实体类
            • processor 处理器相关的包
              • AutowiredProcessor.java 自动注入处理器
              • BaseProcessor.java 基础处理器
              • InterceptorProcessor.java 拦截器处理器
              • RouteProcessor.java 路由处理器
            • utils 工具类相关的包
              • Consts.java 常量类
              • Logger.java 日志记录器类
              • TypeUtils.java 类型工具类

router-annotation 路由注解模块

annotation 存放各种注解类的包

Autowired

自动注入的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.alibaba.android.arouter.facade.annotation

/**
* Annotation for field, which need autowired.
* 用于需要自动注入的字段的注解。
*
* @author zhilong [Contact me.](mailto:zhilong.lzl@alibaba-inc.com)
* @version 1.0
* @since 2017/2/20 下午4:26
*/
@Target(AnnotationTarget.FIELD) // 表示该注解只能用于字段上
@kotlin.annotation.Retention(AnnotationRetention.BINARY) // 表示该注解的生命周期为编译期
annotation class Autowired( // Mark param's name or service name.
// 标记参数的名称或服务名称
val name: String = "", // If required, app will be crash when value is null.
// Primitive type wont be check!
// 如果设置为true,在数值为null时应用程序将崩溃。不会检查原始类型!
val required: Boolean = false, // Description of the field
// 字段的描述信息
val desc: String = ""
)

标记需要注入的字段:在你的类中,标记需要进行自动注入的字段。使用 @Autowired 注解,例如:

1
2
3
4
5
6
7
8
9
10
import com.alibaba.android.arouter.facade.annotation.Autowired;

// ...

public class MyClass {
@Autowired
private MyDependency myDependency;

// ...
}

在这个示例中,myDependency 字段被标记为需要自动注入的依赖对象。

假设你有两个相同类型的依赖对象 MyDependency,但它们在功能上略有不同,你需要指定要注入哪一个。

1
2
3
4
5
6
7
8
9
10
11
12
javaCopy code
import com.alibaba.android.arouter.facade.annotation.Autowired;

public class MyClass {
@Autowired(name = "dependencyA")
private MyDependency dependencyA;

@Autowired(name = "dependencyB")
private MyDependency dependencyB;

// ...
}
Interceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.alibaba.android.arouter.facade.annotation

/**
* 标记拦截器以拦截路由。
* 注意:此注解仅可用于标记#{IInterceptor}的实现!!!
*
* @author Alex [联系我。](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 16/8/23 14:03
*/
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS) // 表示该注解只能用于类上
@kotlin.annotation.Retention(AnnotationRetention.BINARY) // 表示该注解的生命周期为编译期
annotation class Interceptor(
/**
* 拦截器的优先级,ARouter将按优先级执行它们。
*/
val priority: Int,
/**
* 拦截器的名称,可能用于生成javadoc。
*/
val name: String = "Default"
)

要使用 @Interceptor 注解,你需要将其标记在实现了 IInterceptor 接口的类上,以定义一个拦截器。然后,你可以使用这个拦截器来拦截路由操作。下面是使用 @Interceptor 注解的一般步骤:

创建一个实现了 IInterceptor 接口的类,该类将用作拦截器。确保类实现了接口中的 process 方法,该方法定义了拦截器的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kotlinCopy code
import com.alibaba.android.arouter.facade.annotation.Interceptor
import com.alibaba.android.arouter.facade.template.IInterceptor
import com.alibaba.android.arouter.facade.callback.InterceptorCallback

@Interceptor(priority = 1, name = "ExampleInterceptor")
class ExampleInterceptor : IInterceptor {
override fun process(postcard: Postcard?, callback: InterceptorCallback?) {
// 在这里编写拦截器的逻辑
// 可以在进入路由之前或之后执行一些操作

// 最后,调用 callback.onContinue(postcard) 继续路由操作,或者 callback.onInterrupt(exception) 中断路由操作
callback?.onContinue(postcard)
}
}
Param(废弃)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.alibaba.android.arouter.facade.annotation

/**
* 用于标记页面参数的注解。
* 此注解已被弃用,请使用 'Autowired' 代替!
*
* @author Alex [联系我。](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 2016/11/22 18:01
*/
@Target(AnnotationTarget.FIELD) // 表示该注解只能用于字段上
@kotlin.annotation.Retention(AnnotationRetention.BINARY) // 表示该注解的生命周期为编译期
@Deprecated("") // 表示该注解已被弃用
annotation class Param(
/**
* 字段名称
*/
val name: String = "",
/**
* 字段的描述信息
*/
val desc: String = "No desc."
)

既已废弃,不浪费时间

Route
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
package com.alibaba.android.arouter.facade.annotation

/**
* 标记页面可由路由器路由。
*
* @author Alex [联系我。](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 16/8/15 下午9:29
*/
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS) // 表示该注解只能用于类上
@kotlin.annotation.Retention(AnnotationRetention.BINARY) // 表示该注解的生命周期为编译期
annotation class Route(
/**
* 路由的路径
*/
val path: String,
/**
* 用于合并路由,组名必须使用常见单词!!!
*/
val group: String = "",
/**
* 路由的名称,用于生成javadoc。
*/
val name: String = "",
/**
* 额外的数据,可以由用户设置。
* 注意:您应该使用整数数值表示开关,通过位进行标记。例如:10001010101010
*/
val extras: Int = Int.MIN_VALUE,
/**
* 路由的优先级。
*/
val priority: Int = -1
)

这个类定义了一个用于标记页面可由路由器路由的注解 @Route。该注解包含了五个元素,分别表示路由的路径、组名、名称、额外数据和优先级。

创建一个页面类,并在该类上添加 @Route 注解,以标记这个页面可以被路由器路由。

1
2
3
4
5
6
7
import com.alibaba.android.arouter.facade.annotation.Route

// 使用 @Route 注解标记这个页面
@Route(path = "/example/activity")
class ExampleActivity : AppCompatActivity() {
// 页面的代码...
}

在上面的示例中,我们创建了一个名为 ExampleActivity 的页面类,并使用 @Route 注解标记了这个页面的路由路径为 "/example/activity"

enums 包含各种枚举类型的包

RouteType
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
package com.alibaba.android.arouter.facade.enums

/**
* 路由类型的枚举。
*
* @author Alex [联系我。](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 16/8/23 22:33
*/
enum class RouteType(// 未知类型的路由
var id: Int, var className: String
) {
ACTIVITY(0, "android.app.Activity"), // Activity类型的路由
SERVICE(1, "android.app.Service"), // Service类型的路由
PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"), // Provider类型的路由
CONTENT_PROVIDER(-1, "android.app.ContentProvider"), // ContentProvider类型的路由
BOARDCAST(-1, ""), // Broadcast类型的路由
METHOD(-1, ""), // Method类型的路由
FRAGMENT(-1, "android.app.Fragment"), // Fragment类型的路由
UNKNOWN(-1, "Unknown route type");

fun setId(id: Int): RouteType {
this.id = id
return this
}

fun setClassName(className: String): RouteType {
this.className = className
return this
}

companion object {
fun parse(name: String): RouteType {
for (routeType in values()) {
if (routeType.className == name) {
return routeType
}
}
return UNKNOWN
}
}
}
TypeKind
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
package com.alibaba.android.arouter.facade.enums

/**
* 字段类型的种类枚举。
*
* @author Alex [联系我。](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 2017-03-16 19:13:38
*/
enum class TypeKind {
// 基本类型
BOOLEAN, // 布尔类型
BYTE, // 字节类型
SHORT, // 短整型
INT, // 整型
LONG, // 长整型
CHAR, // 字符类型
FLOAT, // 单精度浮点型
DOUBLE, // 双精度浮点型

// 其他类型
STRING, // 字符串类型
SERIALIZABLE, // 可序列化类型
PARCELABLE, // Parcelable类型
OBJECT // 对象类型
}

model 包含模型类的包

RouteMeta
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package com.alibaba.android.arouter.facade.model

import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.miao.router.RouteType

/**
* 包含基本路由信息的类。
*
* @author Alex [联系我。](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 16/8/24 09:45
*/
class RouteMeta {
var type: RouteType? = null // 路由类型
private set

private var rawType: javax.lang.model.element.Element? = null // 路由的原始类型

var destination : Class<*>? = null // 目标类
private set

var path : String? = null // 路由路径
private set

var group: String? = null // 路由分组
private set

var priority = -1 // 优先级,数值越小优先级越高
private set

var extra = 0// 额外数据
private set

var paramsType: Map<String?, Int?>? = null // 参数类型
private set

var name: String? = null

var injectConfig: Map<String, Autowired>? = null // 缓存注入配置信息

constructor() {}

/**
* Type
*
* @param route 路由
* @param destination 目标类
* @param type 类型
*/
constructor(
route: Route,
destination: Class<*>?,
type: RouteType?
) : this(
type,
null,
destination,
route.name(),
route.path(),
route.group(),
null,
route.priority(),
route.extras()
) {
}

/**
* Type
*
* @param route 路由
* @param rawType 原始类型
* @param type 类型
* @param paramsType 参数类型
*/
constructor(
route: Route,
rawType: javax.lang.model.element.Element?,
type: RouteType?,
paramsType: Map<String?, Int?>?
) : this(
type,
rawType,
null,
route.name(),
route.path(),
route.group(),
paramsType,
route.priority(),
route.extras()
) {
}

/**
* Type
*
* @param type 类型
* @param rawType 原始类型
* @param destination 目标类
* @param path 路径
* @param group 分组
* @param paramsType 参数类型
* @param priority 优先级
* @param extra 额外数据
*/
constructor(
type: RouteType?,
rawType: javax.lang.model.element.Element?,
destination: Class<*>?,
name: String?,
path: String?,
group: String?,
paramsType: Map<String?, Int?>?,
priority: Int,
extra: Int
) {
this.type = type
this.name = name
this.destination = destination
this.rawType = rawType
this.path = path
this.group = group
this.paramsType = paramsType
this.priority = priority
this.extra = extra
}

fun setParamsType(paramsType: Map<String?, Int?>?): RouteMeta {
this.paramsType = paramsType
return this
}

fun getRawType(): javax.lang.model.element.Element? {
return rawType
}

fun setRawType(rawType: javax.lang.model.element.Element?): RouteMeta {
this.rawType = rawType
return this
}

fun setType(type: RouteType?): RouteMeta {
this.type = type
return this
}

fun setDestination(destination: Class<*>?): RouteMeta {
this.destination = destination
return this
}

fun setPath(path: String?): RouteMeta {
this.path = path
return this
}

fun setGroup(group: String?): RouteMeta {
this.group = group
return this
}

fun setPriority(priority: Int): RouteMeta {
this.priority = priority
return this
}

fun setExtra(extra: Int): RouteMeta {
this.extra = extra
return this
}

override fun toString(): String {
return "RouteMeta{" +
"type=" + type +
", rawType=" + rawType +
", destination=" + destination +
", path='" + path + '\'' +
", group='" + group + '\'' +
", priority=" + priority +
", extra=" + extra +
", paramsType=" + paramsType +
", name='" + name + '\'' +
'}'
}

companion object {
/**
* For versions of 'compiler' less than 1.0.7, contain 1.0.7
*
* @param type 类型
* @param destination 目标类
* @param path 路径
* @param group 分组
* @param priority 优先级
* @param extra 额外数据
* @return this
*/
fun build(
type: RouteType?,
destination: Class<*>?,
path: String?,
group: String?,
priority: Int,
extra: Int
): RouteMeta {
return RouteMeta(type, null, destination, null, path, group, null, priority, extra)
}

/**
* For versions of 'compiler' greater than 1.0.7
*
* @param type 类型
* @param destination 目标类
* @param path 路径
* @param group 分组
* @param paramsType 参数类型
* @param priority 优先级
* @param extra 额外数据
* @return this
*/
fun build(
type: RouteType?,
destination: Class<*>?,
path: String?,
group: String?,
paramsType: Map<String?, Int?>?,
priority: Int,
extra: Int
): RouteMeta {
return RouteMeta(
type,
null,
destination,
null,
path,
group,
paramsType,
priority,
extra
)
}
}
}

private RouteType type:表示路由的类型,可能是普通路由、自动注入、或者其他类型。
private Element rawType:表示路由的原始类型的元素。
private Class<?> destination:表示目标类,即路由到哪个页面。
private String path:表示路由的路径,用于唯一标识一个路由。
private String group:表示路由的分组,通常用于组织路由。
private int priority:表示路由的优先级,数值越小表示优先级越高。
private int extra:表示额外的数据,可以用于传递一些标记或开关。
private Map<String, Integer> paramsType:表示参数类型的映射。
private String name:表示路由的名称。

RouteMeta 是 Route 原子信息与其构建类

TypeWrapper
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
package com.alibaba.android.arouter.facade.model

import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

/**
* 用于获取目标对象的类型。
*
* @param <T> 泛型类型
* @since 17/10/26 11:56:22
</T> */
class TypeWrapper<T> protected constructor() {
/**
* 获取目标对象的类型。
*
* @return 目标对象的类型
*/
val type: Type // 存储目标对象的类型信息

init {
val superClass = javaClass.genericSuperclass
type =
(superClass as ParameterizedType).actualTypeArguments[0] // 获取泛型类型参数
}
}

通过 Java 反射获取当前类的父类,然后从父类中获取泛型参数的类型信息,并将其赋值给 type 字段。这样,这个类就能够存储目标对象的泛型类型信息。

Android Framework 专项 - Handler(二)

android.os.MessageQueue#next
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
@UnsupportedAppUsage
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;
}
}
重点:nativePollOnce(ptr, nextPollTimeoutMillis);

这是一个关键的方法调用,它在 Android 的消息队列 (MessageQueue) 中起到阻塞等待新消息的作用。

  1. nativePollOnce 是一个本地方法调用,它将当前线程置于休眠状态,直到满足以下任一条件:
    • 有新的消息加入消息队列。
    • 等待时间超过了 nextPollTimeoutMillis
  2. nextPollTimeoutMillis 表示下次轮询的超时时间:
    • 如果为 0,则立即进行轮询,不进入休眠。
    • 如果大于 0,则在指定的时间后唤醒线程进行轮询。
    • 如果为 -1,则线程将无限期休眠,直到有新消息加入并显式唤醒它。
  3. nativePollOnce 的底层实现通常使用 epoll 机制(在 Linux 上)。这种机制允许线程高效地等待多个文件描述符(在这种情况下是消息队列的事件描述符)的状态变化。
  4. 当线程处于休眠状态时,它不会消耗 CPU 资源,这对于节省移动设备的能量非常重要。
  5. 当有新消息发送到队列时(例如通过 Handler.sendMessage()),在 MessageQueue.enqueueMessage() 中会调用 nativeWake()nativeWake() 会向消息队列的事件描述符写入数据,从而触发 epoll 的唤醒机制,让 nativePollOnce 返回,线程继续执行后面的逻辑。

总之,nativePollOnceMessageQueue.next() 方法中的关键步骤,它通过底层的事件等待机制实现了线程的高效休眠和唤醒,从而在没有消息处理时节省资源,在有消息到达时及时响应。


重点: 同步屏障 (Sync Barrier)
1
2
3
4
5
6
7
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());
}

在这段代码中,涉及到了 Android 消息机制中的一个重要概念:**同步屏障 (Sync Barrier)**。

  1. 什么是同步屏障?
    同步屏障是一种特殊的消息,它的特点是其 target 属性为 null
  2. 同步屏障的作用:
    当消息队列的头部遇到同步屏障时,它会暂停处理队列中的同步消息,而只优先处理异步消息
  3. 代码逻辑分析:
    • msg != null && msg.target == null 时,说明当前队列头部是一个同步屏障。
    • 此时,代码进入 do-while 循环,目的是跳过所有同步消息,在队列中寻找下一个异步消息 (msg.isAsynchronous())。
    • 一旦找到异步消息,后续的代码逻辑将只处理这个异步消息。
    • 如果队列中没有异步消息,那么 msg 最终会变成 null,导致 nextPollTimeoutMillis 被设置为 -1,线程进入无限期休眠。
  4. 应用场景:
    同步屏障主要用于提高 UI 绘制等高优先级任务的响应速度。例如,在 View 刷新请求 (Choreographer.doFrame()) 发起时,会向消息队列发送一个同步屏障,并发送一个异步消息来执行实际的渲染任务。这样可以确保渲染任务不会被队列中积压的其他同步消息(如普通的 sendMessage)所阻塞。
  5. 移除屏障:
    当高优先级的任务执行完毕后,必须手动移除该同步屏障,否则普通消息将永远无法得到处理。

通过同步屏障,Android 系统实现了一种精细化的消息调度机制,能够确保 UI 交互的流畅性。

从零开始写一个 ARouter - base 基础功能 与 core 核心功能

  • ARouter
    • router-annotation 路由注解模块

      • src.main.java
        • com.alibaba.android.arouter
          • facade 提供注解和枚举的包
            • annotation 存放各种注解类的包
              • Autowired.java 自动注入的注解
              • Interceptor.java 拦截器的注解
              • Param.java(废弃) 参数注解: 被 Autowired 淘汰
              • Route.java 路由信息注解
            • enums 包含各种枚举类型的包
              • RouteType.java 路由类型的枚举
              • TypeKind.java 类型种类的枚举
            • model 包含模型类的包
              • RouteMeta.java 路由元信息的模型类
              • TypeWrapper.java 存储目标对象的泛型类型信息的类
    • arouter-api ARouter框架的API模块

      • src.main.java
        • com.alibaba.android.arouter
          • base 基础功能相关的包

          • core 核心功能相关的包

          • exception 异常相关的包

            • HandlerException.java 处理异常的类
            • InitException.java 初始化异常的类
            • NoRouteFoundException.java 未找到路由的异常类
          • facade 提供各种服务和回调的包

            • callback 回调相关的包
              • InterceptorCallback.java 拦截器回调的接口
              • NavigationCallback.java 导航回调的接口
              • NoRouteFoundException.java 未找到路由的异常接口
          • service 服务相关的包

            • AutowiredService.java 自动注入服务的接口
            • ClassLoaderService.java 类加载器服务的接口
            • DegradeService.java 降级服务的接口
            • InterceptorService.java 拦截器服务的接口
            • PathReplaceService.java 路径替换服务的接口
            • PretreatmentService.java 预处理服务的接口
            • SerializationService.java 序列化服务的接口
          • template 模板相关的包

            • IInterceptor.java 拦截器接口
            • IInterceptorGroup.java 拦截器分组接口
            • Ilogger.java 日志记录器接口
            • IPolicy.java 策略接口
            • IProvider.java 提供者接口
            • IProviderGroup.java 提供者分组接口
            • IRouteGroup.java 路由分组接口
            • IRouteRoot.java 路由根接口
            • Isyringe.java 注射器接口
            • Postcard.java 路由信息封装类
          • launcher 启动器: 包含一些用于启动ARouter框架的类和线程管理相关的类。

            • _Arouter.java ARouter框架的内部启动类,用于初始化ARouter。
            • Arouter.java ARouter框架的启动类,用于初始化ARouter。
          • thread (线程)包含了与线程管理相关的类。

            • CancelableCountDownLatch.java 可取消的倒计时计数器,用于线程同步。
            • DefaultPoolExecutor.java 默认的线程池执行器,用于执行异步任务。
            • DefaultThreadFactory.java 默认线程工厂,用于创建线程。
          • utils 工具类。

            • ClassUtils.java 用于操作类的实用工具类。
            • Consts.java 包含一些常量值的类。
            • DefaultLogger.java 默认的日志记录器类。
            • MapUtils.java 用于操作地图数据的实用工具类。
            • PackageUtils.java 用于操作包信息的实用工具类。
            • TextUtils.java 用于操作文本数据的实用工具类。
          • arouter-compiler

            • src.main.java
              • com.alibaba.android.arouter
                • compiler 编译相关的包
                  • entity 实体类相关的包
                    • RouteDoc.java 路由文档实体类
                  • processor 处理器相关的包
                    • AutowiredProcessor.java 自动注入处理器
                    • BaseProcessor.java 基础处理器
                    • InterceptorProcessor.java 拦截器处理器
                    • RouteProcessor.java 路由处理器
                  • utils 工具类相关的包
                    • Consts.java 常量类
                    • Logger.java 日志记录器类
                    • TypeUtils.java 类型工具类

arouter-api ARouter框架的API模块

base 基础功能相关的包

UniqueKeyTreeMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.alibaba.android.arouter.base

import java.util.*

/**
* TreeMap with unique key.
*
* @author zhilong [Contact me.](mailto:zhilong.lzl@alibaba-inc.com)
* @version 1.0
* @since 2017/2/22 下午5:01
*/
class UniqueKeyTreeMap<K, V>(private val tipText: String) :
TreeMap<K, V>() {
override fun put(key: K, value: V): V? {
return if (containsKey(key)) {
throw RuntimeException(String.format(tipText, key))
} else {
super.put(key, value)
}
}
}

core 核心功能相关的包

AutowiredLifecyleCallback(废弃)
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
package com.alibaba.android.arouter.core

import android.annotation.TargetApi
import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Build
import android.os.Bundle
import com.alibaba.android.arouter.launcher.ARouter

/**
* LifecycleCallback for autowired.
*
* @author zhilong [Contact me.](mailto:zhilong.lzl@alibaba-inc.com)
* @version 1.0
* @since 2017/2/21 上午11:28
*/
@Deprecated("")
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
class AutowiredLifecycleCallback : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
ARouter.getInstance().inject(activity)
}

override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
}

已经废弃,不废话

AutowiredServiceImpl
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
package com.alibaba.android.arouter.core

import android.content.Context
import android.util.LruCache
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.facade.service.AutowiredService
import com.alibaba.android.arouter.facade.template.ISyringe
import com.alibaba.android.arouter.utils.Consts.SUFFIX_AUTOWIRED

/**
* 自动注入服务的实现。
*
* 作者: zhilong [联系我](mailto:zhilong.lzl@alibaba-inc.com)
* 版本: 1.0
* 创建日期: 2017年2月28日 下午6:08
*/
@Route(path = "/arouter/service/autowired")
class AutowiredServiceImpl : AutowiredService {
private var classCache: LruCache<String, ISyringe>? = null
private var blackList: MutableList<String>? = null

/**
* 初始化方法。
*
* @param context 上下文
*/
fun init(context: Context?) {
classCache = LruCache<String, ISyringe>(50)
blackList = ArrayList()
}

/**
* 自动注入方法。
*
* @param instance 要进行注入的实例
*/
fun autowire(instance: Any) {
doInject(instance, null)
}

/**
* 递归注入方法。
*
* @param instance 调用该方法的实例
* @param parent 父类的Class
*/
private fun doInject(instance: Any, parent: Class<*>?) {
// 如果提供了父类的 Class 对象,则使用父类的 Class;否则,使用实例的 Class
val clazz = parent ?: instance.javaClass
// 获取适用于当前类的注入器实例
val syringe: ISyringe? = getSyringe(clazz)
// 如果存在适用的注入器实例
if (null != syringe) {
// 使用注入器进行注入
syringe.inject(instance)
}
// 获取当前类的父类的 Class 对象
val superClazz = clazz.superclass
// 如果存在父类,并且父类不是 Android 框架类
if (null != superClazz && !superClazz.name.startsWith("android")) {
// 递归调用 doInject 方法,继续为父类进行自动注入
doInject(instance, superClazz)
}
}

/**
* 获取注入器实例。
*
* @param clazz 类的Class
* @return 注入器实例
*/
private fun getSyringe(clazz: Class<*>): ISyringe? {
// 获取类的完整名称
val className = clazz.name
try {
// 检查类名是否在黑名单中,如果不在,则尝试获取对应的注入器
if (!blackList!!.contains(className)) {
// 从缓存中尝试获取注入器实例
var syringeHelper: ISyringe? = classCache!![className]
// 如果缓存中没有该注入器实例
if (null == syringeHelper) {
// 动态加载并创建注入器实例
syringeHelper = Class.forName(
clazz.name + SUFFIX_AUTOWIRED
).getConstructor()
.newInstance() as ISyringe
// 将创建的注入器实例缓存起来,以便下次使用
classCache!!.put(className, syringeHelper)
}
// 返回获取到的注入器实例
return syringeHelper
}
} catch (e: Exception) {
// 如果在获取注入器的过程中发生异常,将类名添加到黑名单中,表示该实例无需自动注入
blackList!!.add(className)
}
// 如果无法获取注入器实例,返回 null
return null
}
}

doInject 方法用于自动注入依赖到给定的实例(instance)中。

InstrumentationHook(废弃)
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
package com.alibaba.android.arouter.core

import android.app.Activity
import android.app.Instrumentation
import android.content.Intent
import com.alibaba.android.arouter.launcher.ARouter
import com.alibaba.android.arouter.utils.Consts
import com.alibaba.android.arouter.utils.TextUtils

/**
* 使用 ARouter.getInstance().inject(this) 来进行注入!
*
* Hook Instrumentation,为 Activity 的字段注入值。
* 仅支持普通 Activity,不包括单元测试。
*
* 作者:Alex [联系我](mailto:zhilong.liu@aliyun.com)
* 版本:1.0
* 创建日期:2016年11月24日 16:42
*/
@Deprecated("")
class InstrumentationHook : Instrumentation() {
/**
* Hook Instrumentation 的 newActivity 方法,进行注入。
*
* 执行进程的 [Activity] 对象的实例化。默认实现提供正常的系统行为。
*
* @param cl 用于实例化对象的类加载器。
* @param className 实现 Activity 对象的类的名称。
* @param intent 指定要实例化的活动类的 Intent 对象。
* @return 新创建的 Activity 对象。
*/
@Throws(
InstantiationException::class,
IllegalAccessException::class,
ClassNotFoundException::class
)
override fun newActivity(
cl: ClassLoader, className: String,
intent: Intent
): Activity {

// return (Activity)cl.loadClass(className).newInstance();
// 使用类加载器加载目标 Activity 类的定义
val targetActivity = cl.loadClass(className)
// 创建目标 Activity 的实例
val instanceOfTarget = targetActivity.newInstance()
// 检查是否可以自动注入
if (ARouter.canAutoInject()) {
// 从 Intent 中获取自动注入的参数
val autoInjectParams = intent.getStringArrayExtra(ARouter.AUTO_INJECT)
if (null != autoInjectParams && autoInjectParams.isNotEmpty()) {
// 遍历参数列表
for (paramsName in autoInjectParams) {
// 从 Intent 的 extras 中获取参数值
val value = intent.extras!![TextUtils.getLeft(paramsName)]
if (null != value) {
try {
// 获取目标 Activity 中的字段
val injectField =
targetActivity.getDeclaredField(TextUtils.getLeft(paramsName))
// 设置字段可访问
injectField.isAccessible = true
// 将提取的值注入到目标 Activity 的字段中
injectField[instanceOfTarget] = value
} catch (e: Exception) {
// 记录错误日志,包括异常信息
ARouter.logger.error(
Consts.TAG,
"为 Activity 注入值时发生错误![" + e.message + "]"
)
}
}
}
}
}
// 返回已注入值的目标 Activity 实例
return instanceOfTarget as Activity
}
}

已废弃,不废话

InterceptorServiceImpl
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.alibaba.android.arouter.core

import android.content.Context
import com.alibaba.android.arouter.exception.HandlerException
import com.alibaba.android.arouter.facade.Postcard
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.facade.callback.InterceptorCallback
import com.alibaba.android.arouter.facade.service.InterceptorService
import com.alibaba.android.arouter.facade.template.IInterceptor
import com.alibaba.android.arouter.launcher.ARouter.logger
import com.alibaba.android.arouter.thread.CancelableCountDownLatch
import com.alibaba.android.arouter.utils.Consts.TAG
import com.alibaba.android.arouter.utils.MapUtils
import java.util.concurrent.TimeUnit

/**
* 所有拦截器的实现类
*
* @author zhilong [联系我](mailto:zhilong.lzl@alibaba-inc.com)
* @version 1.0
* @since 2017/2/23 下午2:09
*/
@Route(path = "/arouter/service/interceptor")
class InterceptorServiceImpl : InterceptorService {
/**
* 执行拦截操作
*
* @param postcard 路由信息,包含了路由的相关信息和配置。
* @param callback 拦截回调,用于在拦截器流程中通知下一步操作。
*/
fun doInterceptions(postcard: Postcard, callback: InterceptorCallback) {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
// 检查拦截器是否已经初始化
checkInterceptorsInitStatus()

// 如果拦截器未初始化完成,中断导航并抛出异常
if (!interceptorHasInit) {
callback.onInterrupt(HandlerException("拦截器初始化花费太长时间。"))
return
}

// 在后台线程中执行拦截器操作
LogisticsCenter.executor.execute(Runnable {
val interceptorCounter = CancelableCountDownLatch(Warehouse.interceptors.size())
try {
// 依次执行拦截器
_execute(0, interceptorCounter, postcard)

// 等待拦截器执行完成,超时时间由路由配置决定
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS)

// 如果有未执行的拦截器,取消导航
if (interceptorCounter.getCount() > 0) { // 如果没有返回任何内容,取消导航。
callback.onInterrupt(HandlerException("拦截器处理超时。"))
} else if (null != postcard.getTag()) { // 如果标签中有异常信息。
callback.onInterrupt(postcard.getTag() as Throwable)
} else {
// 所有拦截器执行完毕,继续路由导航
callback.onContinue(postcard)
}
} catch (e: Exception) {
// 拦截器执行过程中出现异常,中断导航并传递异常信息
callback.onInterrupt(e)
}
})
} else {
// 没有注册拦截器,直接继续路由导航
callback.onContinue(postcard)
}
}

/**
* 初始化拦截器
*
* @param context 上下文对象,用于在拦截器初始化时可能需要的上下文信息。
*/
fun init(context: Context?) {
LogisticsCenter.executor.execute(Runnable {
// 检查是否有已注册的拦截器
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for ((_, interceptorClass): Map.Entry<Int?, Class<out IInterceptor?>> in Warehouse.interceptorsIndex.entrySet()) {
try {
// 实例化拦截器
val iInterceptor: IInterceptor =
interceptorClass.getConstructor().newInstance()

// 调用拦截器的初始化方法,传入上下文信息
iInterceptor.init(context)

// 将拦截器添加到仓库中,以供后续使用
Warehouse.interceptors.add(iInterceptor)
} catch (ex: Exception) {
// 如果初始化过程中发生异常,抛出自定义的异常
throw HandlerException(TAG.toString() + "ARouter初始化拦截器错误!名称 = [" + interceptorClass.name + "],原因 = [" + ex.message + "]")
}
}

// 标记拦截器已经初始化完成
interceptorHasInit = true

// 记录日志,表示拦截器初始化已完成
logger.info(TAG, "ARouter拦截器初始化完成。")

// 通知等待的线程,拦截器已经初始化完成
synchronized(interceptorInitLock) { interceptorInitLock.notifyAll() }
}
})
}

companion object {
private var interceptorHasInit = false
private val interceptorInitLock = Any()

/**
* 执行拦截器
*
* @param index 当前拦截器索引
* @param counter 拦截器计数器
* @param postcard 路由信息
*/
private fun _execute(index: Int, counter: CancelableCountDownLatch, postcard: Postcard) {
if (index < Warehouse.interceptors.size()) {
val iInterceptor: IInterceptor = Warehouse.interceptors.get(index)
iInterceptor.process(postcard, object : InterceptorCallback() {
fun onContinue(postcard: Postcard) {
// 最后一个拦截器执行完成,没有异常。
counter.countDown()
_execute(
index + 1,
counter,
postcard
) // 当计数器减少时,继续执行,但是索引大于拦截器的大小,此时不会继续执行。
}

fun onInterrupt(exception: Throwable?) {
// 最后一个拦截器执行出现严重异常。
postcard.setTag(
exception ?: HandlerException("没有消息。")
) // 保存异常消息以备份。
counter.cancel()
// 注意,可能回调中的线程已经更改,
// 然后捕获块(L207)将无效。
// 最糟糕的情况是线程更改为主线程,然后如果抛出此异常,则应用程序将崩溃!
// if (!Looper.getMainLooper().equals(Looper.myLooper())) { // 如果线程是主线程,则不应抛出异常。
// throw new HandlerException(exception.getMessage());
// }
}
})
}
}

private fun checkInterceptorsInitStatus() {
synchronized(interceptorInitLock) {
while (!interceptorHasInit) {
try {
interceptorInitLock.wait((10 * 1000).toLong())
} catch (e: InterruptedException) {
throw HandlerException(TAG.toString() + "拦截器初始化花费太长时间错误!原因 = [" + e.message + "]")
}
}
}
}
}
}

这个类是ARouter(Android路由框架)的核心拦截器服务实现类,它具有以下作用:

  1. 拦截器管理: 该类负责管理ARouter框架中的拦截器。拦截器是在路由导航过程中执行的一系列操作,用于处理路由请求或者对路由进行拦截和修改。
  2. 拦截器执行: 通过doInterceptions方法,该类执行了一系列的拦截器操作。在路由导航之前,它会依次调用已注册的拦截器,检查是否需要拦截路由请求或对请求进行修改。如果有拦截器拦截了请求,将触发拦截器的onInterrupt方法,否则,将继续执行下一个拦截器,直到所有拦截器都完成或者发生了异常。
  3. 拦截器初始化: 通过init方法,该类还负责初始化所有的拦截器。在ARouter框架初始化的过程中,会注册各种拦截器,这些拦截器需要在合适的时机进行初始化,以便在路由导航时能够正确地执行。
  4. 线程控制: 该类使用CancelableCountDownLatch来管理拦截器的执行,确保在所有拦截器执行完成或者超时时能够继续路由导航操作。同时,它还使用锁来控制拦截器的初始化过程,以确保在初始化完成之前不会执行路由导航。
LogisticsCenter
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
package com.alibaba.android.arouter.core

import android.content.Context
import android.net.Uri
import com.alibaba.android.arouter.exception.HandlerException
import com.alibaba.android.arouter.exception.NoRouteFoundException
import com.alibaba.android.arouter.facade.Postcard
import com.alibaba.android.arouter.facade.enums.TypeKind
import com.alibaba.android.arouter.facade.model.RouteMeta
import com.alibaba.android.arouter.facade.template.IInterceptorGroup
import com.alibaba.android.arouter.facade.template.IProvider
import com.alibaba.android.arouter.facade.template.IProviderGroup
import com.alibaba.android.arouter.facade.template.IRouteGroup
import com.alibaba.android.arouter.facade.template.IRouteRoot
import com.alibaba.android.arouter.launcher.ARouter
import com.alibaba.android.arouter.launcher.ARouter.logger
import com.alibaba.android.arouter.utils.ClassUtils
import com.alibaba.android.arouter.utils.Consts
import com.alibaba.android.arouter.utils.Consts.AROUTER_SP_CACHE_KEY
import com.alibaba.android.arouter.utils.Consts.AROUTER_SP_KEY_MAP
import com.alibaba.android.arouter.utils.Consts.DOT
import com.alibaba.android.arouter.utils.Consts.ROUTE_ROOT_PAKCAGE
import com.alibaba.android.arouter.utils.Consts.SDK_NAME
import com.alibaba.android.arouter.utils.Consts.SEPARATOR
import com.alibaba.android.arouter.utils.Consts.SUFFIX_INTERCEPTORS
import com.alibaba.android.arouter.utils.Consts.SUFFIX_PROVIDERS
import com.alibaba.android.arouter.utils.Consts.SUFFIX_ROOT
import com.alibaba.android.arouter.utils.Consts.TAG
import com.alibaba.android.arouter.utils.MapUtils
import com.alibaba.android.arouter.utils.PackageUtils
import com.alibaba.android.arouter.utils.TextUtils
import java.lang.Boolean
import java.lang.reflect.InvocationTargetException
import java.util.*
import java.util.concurrent.ThreadPoolExecutor
import kotlin.Exception
import kotlin.Int
import kotlin.String
import kotlin.Throwable
import kotlin.Throws
import kotlin.arrayOf

/**
* LogisticsCenter 包含了所有的路由映射信息。
*
* 1. 在首次使用时创建实例。
* 2. 处理多模块之间的映射关系(*)
* 3. 解决重复组定义的复杂逻辑
*
* @author Alex [联系我](mailto:zhilong.liu@aliyun.com)
* @version 1.0
* @since 16/8/23 15:02
*/
object LogisticsCenter {
private var mContext: Context? = null
var executor: ThreadPoolExecutor? = null
private var registerByPlugin = false

/**
* arouter-auto-register 插件将在这个方法中生成代码
* 调用这个方法来注册所有的路由、拦截器和提供者
*/
private fun loadRouterMap() {
registerByPlugin = false
// 自动生成的注册代码由 Gradle 插件 arouter-auto-register 生成
// 看起来像下面这样:
// registerRouteRoot(new ARouter..Root..modulejava());
// registerRouteRoot(new ARouter..Root..modulekotlin());
}

/**
* 根据类名注册
* 为了解决主 dex 文件过大的问题,牺牲了一些效率
*/
private fun register(className: String) {
if (!TextUtils.isEmpty(className)) {
try {
val clazz = Class.forName(className)
val obj = clazz.getConstructor().newInstance()
if (obj is IRouteRoot) {
registerRouteRoot(obj as IRouteRoot)
} else if (obj is IProviderGroup) {
registerProvider(obj as IProviderGroup)
} else if (obj is IInterceptorGroup) {
registerInterceptor(obj as IInterceptorGroup)
} else {
logger.info(
TAG, "注册失败,类名:" + className
+ " 应该实现其中一个接口 IRouteRoot/IProviderGroup/IInterceptorGroup。"
)
}
} catch (e: Exception) {
logger.error(TAG, "注册类错误:$className", e)
}
}
}

/**
* 用于 arouter-auto-register 插件注册路由的方法
* @param routeRoot IRouteRoot 实现类,位于包 com.alibaba.android.arouter.core.routers
*/
private fun registerRouteRoot(routeRoot: IRouteRoot?) {
markRegisteredByPlugin()
if (routeRoot != null) {
routeRoot.loadInto(Warehouse.groupsIndex)
}
}

/**
* 用于 arouter-auto-register 插件注册拦截器的方法
* @param interceptorGroup IInterceptorGroup 实现类,位于包 com.alibaba.android.arouter.core.routers
*/
private fun registerInterceptor(interceptorGroup: IInterceptorGroup?) {
markRegisteredByPlugin()
if (interceptorGroup != null) {
interceptorGroup.loadInto(Warehouse.interceptorsIndex)
}
}

/**
* 用于 arouter-auto-register 插件注册提供者的方法
* @param providerGroup IProviderGroup 实现类,位于包 com.alibaba.android.arouter.core.routers
*/
private fun registerProvider(providerGroup: IProviderGroup?) {
markRegisteredByPlugin()
if (providerGroup != null) {
providerGroup.loadInto(Warehouse.providersIndex)
}
}

/**
* 标记已由 arouter-auto-register 插件注册
*/
private fun markRegisteredByPlugin() {
if (!registerByPlugin) {
registerByPlugin = true
}
}

/**
* LogisticsCenter 初始化,加载所有路由信息到内存中,需要在首次使用时进行初始化。
*/
@Synchronized
@Throws(HandlerException::class)
fun init(context: Context, tpe: ThreadPoolExecutor?) {
mContext = context
executor = tpe
try {
var startInit = System.currentTimeMillis()
// 首先通过插件加载路由信息
loadRouterMap()
if (registerByPlugin) {
logger.info(TAG, "通过 arouter-auto-register 插件加载路由映射信息。")
} else {
val routerMap: Set<String>

// 在调试模式或安装新版本时,每次都会重建路由映射
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
logger.info(TAG, "在调试模式下或安装新版本,重新构建路由映射。")
// 这些类是由 arouter-compiler 自动生成的
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE)
if (!routerMap.isEmpty()) {
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE)
.edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply()
}
PackageUtils.updateVersion(context) // 保存新版本名,当路由映射更新完成时使用
} else {
logger.info(TAG, "从缓存中加载路由映射信息。")
routerMap = HashSet(
context.getSharedPreferences(
AROUTER_SP_CACHE_KEY,
Context.MODE_PRIVATE
).getStringSet(AROUTER_SP_KEY_MAP, HashSet())
)
}
logger.info(
TAG,
"找到路由映射信息,映射大小 = " + routerMap.size + ",耗时 " + (System.currentTimeMillis() - startInit) + " 毫秒。"
)
startInit = System.currentTimeMillis()
for (className in routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// 这是根元素之一,加载根元素
(Class.forName(className).getConstructor()
.newInstance() as IRouteRoot).loadInto(Warehouse.groupsIndex)
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// 加载拦截器映射信息
(Class.forName(className).getConstructor()
.newInstance() as IInterceptorGroup).loadInto(Warehouse.interceptorsIndex)
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// 加载提供者映射信息
(Class.forName(className).getConstructor()
.newInstance() as IProviderGroup).loadInto(Warehouse.providersIndex)
}
}
}
logger.info(
TAG,
"加载根元素完成,耗时 " + (System.currentTimeMillis() - startInit) + " 毫秒。"
)
if (Warehouse.groupsIndex.size() === 0) {
logger.error(TAG, "未找到映射文件,请检查您的配置!")
}
if (ARouter.debuggable()) {
logger.debug(
TAG,
java.lang.String.format(
Locale.getDefault(),
"LogisticsCenter 已经加载,GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]",
Warehouse.groupsIndex.size(),
Warehouse.interceptorsIndex.size(),
Warehouse.providersIndex.size()
)
)
}
} catch (e: Exception) {
throw HandlerException(TAG.toString() + "ARouter 初始化物流中心异常! [" + e.message + "]")
}
}

/**
* 根据服务名构建 Postcard
*
* @param serviceName 接口名
* @return Postcard
*/
fun buildProvider(serviceName: String?): Postcard? {
val meta: RouteMeta = Warehouse.providersIndex.get(serviceName)
return if (null == meta) {
null
} else {
Postcard(meta.getPath(), meta.getGroup())
}
}

/**
* 根据路由元信息完成 Postcard 对象
*
* @param postcard 不完整的 Postcard,应由此方法完成。
*/
@Synchronized
fun completion(postcard: Postcard?) {
if (null == postcard) {
throw NoRouteFoundException(TAG.toString() + "没有 Postcard!")
}
val routeMeta: RouteMeta = Warehouse.routes.get(postcard.getPath())
if (null == routeMeta) {
// 可能不存在或尚未加载
if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
throw NoRouteFoundException(TAG.toString() + "没有匹配路径 [" + postcard.getPath() + "],在组 [" + postcard.getGroup() + "] 中。")
} else {
// 加载路由信息并缓存到内存中,然后从路由元信息中删除
try {
if (ARouter.debuggable()) {
logger.debug(
TAG,
java.lang.String.format(
Locale.getDefault(),
"开始加载组 [%s],由 [%s] 触发。",
postcard.getGroup(),
postcard.getPath()
)
)
}
addRouteGroupDynamic(postcard.getGroup(), null)
if (ARouter.debuggable()) {
logger.debug(
TAG,
java.lang.String.format(
Locale.getDefault(),
"组 [%s] 已经加载,由 [%s] 触发。",
postcard.getGroup(),
postcard.getPath()
)
)
}
} catch (e: Exception) {
throw HandlerException(TAG.toString() + "加载组元信息时发生致命异常。 [" + e.message + "]")
}
completion(postcard) // 重新加载
}
} else {
postcard.setDestination(routeMeta.getDestination())
postcard.setType(routeMeta.getType())
postcard.setPriority(routeMeta.getPriority())
postcard.setExtra(routeMeta.getExtra())
val rawUri: Uri = postcard.getUri()
if (null != rawUri) { // 尝试将参数设置到 Bundle 中
val resultMap: Map<String, String> = TextUtils.splitQueryParameters(rawUri)
val paramsType: Map<String, Int?> = routeMeta.getParamsType()
if (MapUtils.isNotEmpty(paramsType)) {
// 根据参数类型设置值,仅对使用 @Param 注解的参数有效
for ((key, value): Map.Entry<String, Int?> in paramsType) {
setValue(
postcard,
value,
key,
resultMap[key]
)
}

// 保存需要自动注入的参数名
postcard.getExtras().putStringArray(
ARouter.AUTO_INJECT,
paramsType.keys.toArray(arrayOf<String>())
)
}

// 保存原始 URI
postcard.withString(ARouter.RAW_URI, rawUri.toString())
}
when (routeMeta.getType()) {
PROVIDER -> {
// 这是提供者,所以必须实现 IProvider 接口
val providerMeta: Class<out IProvider?> = routeMeta.getDestination()
var instance: IProvider? = Warehouse.providers.get(providerMeta)
if (null == instance) { // 没有此提供者的实例
val provider: IProvider
try {
provider = providerMeta.getConstructor().newInstance()
provider.init(mContext)
Warehouse.providers.put(providerMeta, provider)
instance = provider
} catch (e: Exception) {
logger.error(TAG, "初始化提供者失败!", e)
throw HandlerException("初始化提供者失败!")
}
}
postcard.setProvider(instance)
postcard.greenChannel() // 提供者应跳过所有拦截器
}
FRAGMENT -> postcard.greenChannel() // Fragment 不需要拦截器
else -> {}
}
}
}

/**
* 根据已知类型设置值
*
* @param postcard postcard
* @param typeDef 类型
* @param key 键
* @param value 值
*/
private fun setValue(postcard: Postcard, typeDef: Int?, key: String, value: String?) {
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
return
}
try {
if (null != typeDef) {
if (typeDef === TypeKind.BOOLEAN.ordinal()) {
postcard.withBoolean(key, Boolean.parseBoolean(value))
} else if (typeDef === TypeKind.BYTE.ordinal()) {
postcard.withByte(key, value!!.toByte())
} else if (typeDef === TypeKind.SHORT.ordinal()) {
postcard.withShort(key, value!!.toShort())
} else if (typeDef === TypeKind.INT.ordinal()) {
postcard.withInt(key, value!!.toInt())
} else if (typeDef === TypeKind.LONG.ordinal()) {
postcard.withLong(key, value!!.toLong())
} else if (typeDef === TypeKind.FLOAT.ordinal()) {
postcard.withFloat(key, value!!.toFloat())
} else if (typeDef === TypeKind.DOUBLE.ordinal()) {
postcard.withDouble(key, value!!.toDouble())
} else if (typeDef === TypeKind.STRING.ordinal()) {
postcard.withString(key, value)
} else if (typeDef === TypeKind.PARCELABLE.ordinal()) {
// TODO : 如何使用字符串描述可传递的值?
} else if (typeDef === TypeKind.OBJECT.ordinal()) {
postcard.withString(key, value)
} else { // 兼容编译器 SDK 1.0.3,在该版本中,字符串类型 = 18
postcard.withString(key, value)
}
} else {
postcard.withString(key, value)
}
} catch (ex: Throwable) {
logger.warning(Consts.TAG, "LogisticsCenter setValue 失败!" + ex.message)
}
}

/**
* 挂起业务,清除缓存。
*/
fun suspend() {
Warehouse.clear()
}

@Synchronized
@Throws(
NoSuchMethodException::class,
IllegalAccessException::class,
InvocationTargetException::class,
InstantiationException::class
)
fun addRouteGroupDynamic(groupName: String?, group: IRouteGroup?) {
if (Warehouse.groupsIndex.containsKey(groupName)) {
// 如果已包含此组,但尚未加载
// 先加载此组,因为动态路由具有较高的优先级。
Warehouse.groupsIndex.get(groupName).getConstructor().newInstance()
.loadInto(Warehouse.routes)
Warehouse.groupsIndex.remove(groupName)
}

// 覆盖旧组。
if (null != group) {
group.loadInto(Warehouse.routes)
}
}
}

这个类是ARouter库的核心组件之一,它的主要作用是负责管理和维护ARouter路由框架中的各种映射关系和配置信息,以便实现路由功能。以下是这个类的主要作用描述:

  1. 加载路由映射信息: LogisticsCenter负责加载和管理所有的路由映射信息。这些路由映射信息包括路由路径、路由分组、拦截器、提供者等相关信息,它们在ARouter框架中用于实现路由跳转和服务提供。

  2. 支持自动注册: 通过ARouter的插件机制,LogisticsCenter可以支持自动注册路由信息,使得开发者无需手动配置路由信息,提高了开发效率。插件会自动生成代码来调用LogisticsCenter的方法注册路由信息。

  3. 初始化和管理线程池: LogisticsCenter负责初始化和管理线程池,用于异步加载路由信息和执行路由任务。线程池的管理有助于提高ARouter框架的性能和并发处理能力。

  4. 动态加载路由信息: 当需要跳转到某个路由时,LogisticsCenter会根据路由信息动态加载相关的路由元信息,包括路由组信息和拦截器信息,以便进行路由跳转和拦截器处理。

  5. 提供路由跳转和服务提供支持: LogisticsCenter提供了一系列方法,用于构建路由跳转的Postcard对象和获取服务提供者的实例。它还负责处理路由跳转的逻辑,包括路由路径匹配、拦截器处理和服务提供。

  6. 支持路由信息的缓存和更新: LogisticsCenter支持路由信息的缓存和更新,以提高ARouter框架的性能。当路由信息有更新时,可以通过插件机制重新生成路由映射信息。

总之,LogisticsCenter是ARouter框架中的核心组件,它通过加载、管理和动态获取路由信息,实现了路由跳转和服务提供的功能,提供了便捷的路由框架和服务化解决方案。

Warehouse
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
package com.alibaba.android.arouter.core

import com.alibaba.android.arouter.base.UniqueKeyTreeMap
import com.alibaba.android.arouter.facade.model.RouteMeta
import com.alibaba.android.arouter.facade.template.IInterceptor
import com.alibaba.android.arouter.facade.template.IProvider
import com.alibaba.android.arouter.facade.template.IRouteGroup

/**
* 路由元信息和其他数据的存储仓库。
*
* Warehouse(仓库)负责存储路由元信息以及其他相关数据。
*
* @author zhilong [Contact me.](mailto:zhilong.lzl@alibaba-inc.com)
* @version 1.0
* @since 2017/2/23 下午1:39
*/
internal object Warehouse {
// 缓存路由组和路由元信息
var groupsIndex: MutableMap<String, Class<out IRouteGroup?>> =
HashMap<String, Class<out IRouteGroup?>>()
var routes: MutableMap<String, RouteMeta> = HashMap<String, RouteMeta>()

// 缓存服务提供者
var providers: MutableMap<Class<*>, IProvider> = HashMap<Class<*>, IProvider>()
var providersIndex: MutableMap<String, RouteMeta> = HashMap<String, RouteMeta>()

// 缓存拦截器
var interceptorsIndex: MutableMap<Int, Class<out IInterceptor?>> =
UniqueKeyTreeMap("多个拦截器使用相同的优先级 [%s]")
var interceptors: MutableList<IInterceptor> = ArrayList<IInterceptor>()

/**
* 清空仓库中的数据。
*/
fun clear() {
routes.clear()
groupsIndex.clear()
providers.clear()
providersIndex.clear()
interceptors.clear()
interceptorsIndex.clear()
}
}

这个类是ARouter框架内部的一个存储仓库,用于缓存路由元信息、路由组信息、服务提供者信息以及拦截器信息等相关数据。这些数据在ARouter框架中用于实现路由跳转和服务提供功能。

Android Framework 专项 - Handler(三)

继续:android.os.Looper#loopOnce
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
}
重点:msg.target.dispatchMessage(msg);

这是 loopOnce 中最核心的一行代码。

  1. 分发者msg.target 是发送该消息的 Handler 实例。
  2. 分发逻辑:它决定了消息最终由谁来处理。
  3. 调用链路:在 dispatchMessage 内部,会按照优先级进行回调。

android.os.Handler#dispatchMessage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
消息处理的优先级

dispatchMessage 的源码清晰地展示了 Handler 处理消息的优先级顺序:

  1. 最高优先级:Message 的 callback
    如果你通过 handler.post(Runnable) 发送消息,那么 msg.callback 就是这个 Runnable。此时直接执行 run() 方法。
  2. 中等优先级:Handler 的 mCallback
    如果你在构造 Handler 时传入了 Handler.Callback 接口实例:
    Handler(Looper.myLooper(), callback)
    那么会先执行这个 callback。如果该 callback 返回 true,则消息处理结束。
  3. 最低优先级:Handler 的 handleMessage 方法
    这是最常用的方式,即子类重写 handleMessage。只有当前两项都不满足(或第2项返回 false)时,才会执行到这里。

这种优先级设计为开发者提供了灵活的拦截和处理消息的方式。


总结:Handler 机制的完整闭环

  1. 发送Handler 通过 sendMessage 系列方法,将 Message(持有 target 引用)插入 MessageQueue
  2. 入队MessageQueue 根据执行时间 when 对消息进行优先级排序。
  3. 循环:主线程的 Looper.loop() 开启死循环,不断调用 MessageQueue.next() 取出消息。
  4. 阻塞:如果没有消息,next() 内部调用 nativePollOnce 让主线程进入高效休眠。
  5. 分发:一旦有消息,Looper 调用 msg.target.dispatchMessage(msg)
  6. 回调Handler 根据优先级,最终回调到 handleMessage 或执行 Runnable

从零开始写一个 ARouter - exception 异常与 callback 回调

  • ARouter
    • router-annotation 路由注解模块
      • src.main.java

        • com.alibaba.android.arouter
          • facade 提供注解和枚举的包
            • annotation 存放各种注解类的包
              • Autowired.java 自动注入的注解
              • Interceptor.java 拦截器的注解
              • Param.java(废弃) 参数注解: 被 Autowired 淘汰
              • Route.java 路由信息注解
            • enums 包含各种枚举类型的包
              • RouteType.java 路由类型的枚举
              • TypeKind.java 类型种类的枚举
            • model 包含模型类的包
              • RouteMeta.java 路由元信息的模型类
              • TypeWrapper.java 存储目标对象的泛型类型信息的类
      • arouter-api ARouter框架的API模块

        • src.main.java
          • com.alibaba.android.arouter
            • base 基础功能相关的包
              • UniqueKeyTreeMap.java 唯一键树形映射的类
            • core 核心功能相关的包
              • AutowiredLifecyleCallback.java(废弃) 自动注入生命周期回调的类
              • AutowiredServiceImpl.java 自动注入服务的实现类
              • InstrumentationHook.java(废弃) 仪表钩子的类
              • InterceptorServiceImpl.java 拦截器服务的实现类
              • LogisticsCenter.java 物流中心的类
              • Warehouse.java 仓库的类
            • exception 异常相关的包
            • facade 提供各种服务和回调的包
            • service 服务相关的包
              • AutowiredService.java 自动注入服务的接口
              • ClassLoaderService.java 类加载器服务的接口
              • DegradeService.java 降级服务的接口
              • InterceptorService.java 拦截器服务的接口
              • PathReplaceService.java 路径替换服务的接口
              • PretreatmentService.java 预处理服务的接口
              • SerializationService.java 序列化服务的接口
            • template 模板相关的包
              • IInterceptor.java 拦截器接口
              • IInterceptorGroup.java 拦截器分组接口
              • Ilogger.java 日志记录器接口
              • IPolicy.java 策略接口
              • IProvider.java 提供者接口
              • IProviderGroup.java 提供者分组接口
              • IRouteGroup.java 路由分组接口
              • IRouteRoot.java 路由根接口
              • Isyringe.java 注射器接口
              • Postcard.java 路由信息封装类
            • launcher 启动器: 包含一些用于启动ARouter框架的类和线程管理相关的类。
              • _Arouter.java ARouter框架的内部启动类,用于初始化ARouter。
              • Arouter.java ARouter框架的启动类,用于初始化ARouter。
            • thread (线程)包含了与线程管理相关的类。
              • CancelableCountDownLatch.java 可取消的倒计时计数器,用于线程同步。
              • DefaultPoolExecutor.java 默认的线程池执行器,用于执行异步任务。
              • DefaultThreadFactory.java 默认线程工厂,用于创建线程。
            • utils 工具类。
              • ClassUtils.java 用于操作类的实用工具类。
              • Consts.java 包含一些常量值的类。
              • DefaultLogger.java 默认的日志记录器类。
              • MapUtils.java 用于操作地图数据的实用工具类。
              • PackageUtils.java 用于操作包信息的实用工具类。
              • TextUtils.java 用于操作文本数据的实用工具类。
      • arouter-compiler

        • src.main.java
          • com.alibaba.android.arouter
            • compiler 编译相关的包
              • entity 实体类相关的包
                • RouteDoc.java 路由文档实体类
              • processor 处理器相关的包
                • AutowiredProcessor.java 自动注入处理器
                • BaseProcessor.java 基础处理器
                • InterceptorProcessor.java 拦截器处理器
                • RouteProcessor.java 路由处理器
              • utils 工具类相关的包
                • Consts.java 常量类
                • Logger.java 日志记录器类
                • TypeUtils.java 类型工具类

Android 核心机制:Handler、Looper 与 MessageQueue 的持有关系详解

理解 Handler 机制不仅要看消息如何分发,更要理清各组件之间的强引用(持有)关系。这不仅是面试的高频考点,也是分析内存泄漏的底层基础。

1. 核心对象持有关系一览表

持有者 (Owner) 被持有者 (Owned) 持有方式 作用与意义
Thread Looper ThreadLocal 确保每个线程最多只有一个 Looper 实例,且线程私有。
Looper MessageQueue 成员变量 mQueue Looper 循环时不断从这个队列中通过 next() 取消息。
Handler Looper 成员变量 mLooper Handler 发送消息时需要知道往哪个 Looper 的队列里投递。
Handler MessageQueue 成员变量 mQueue 性能优化,避免每次发消息都通过 Looper 去间接获取。
MessageQueue Message 链表结构 mMessages 消息队列本质上是一个以 Message 为节点的单向链表。
Message Handler 成员变量 target 核心点:记录该消息由谁发送,以便 Looper 取出后回调正确的 dispatchMessage

2. 深度解析:为什么会内存泄漏?

通过上面的持有关系,我们可以推导出一条“致命”的引用链:

主线程 (Thread)
↓ (ThreadLocal)
Looper
↓ (mQueue)
MessageQueue
↓ (mMessages 链表)
Message (尚未到期的延时消息)
↓ (target)
Handler (匿名内部类/非静态内部类)
↓ (隐式持有)
Activity

结论:只要消息队列中还有一个 target 指向该 Handler 的消息没处理完,整个 Activity 就无法被 GC 回收。


3. Handler 与 Looper 的解耦设计

虽然 Handler 持有 Looper,但它们的生命周期是不同的:

组件 生命周期 数量关系
Looper 与线程同生共死。 一个线程只能有 1 个。
Handler 随业务逻辑创建与销毁。 一个线程可以对应 N 个。

设计精妙之处
Handler 在构造时绑定的 Looper 决定了它“在哪个线程处理消息”。这种设计允许我们在子线程 A 中创建 Handler 并在构造时传入主线程的 Looper,从而实现“子线程发消息,主线程收消息”的跨线程切换。


4. 关键代码支撑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Handler.java 构造函数
public Handler(@Nullable Callback callback, boolean async) {
mLooper = Looper.myLooper(); // 从 ThreadLocal 获取当前线程的 Looper
if (mLooper == null) {
throw new RuntimeException("Can't create handler inside thread...");
}
mQueue = mLooper.mQueue; // 直接持有 Looper 的队列引用
}

// Handler.java 发送消息
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 关键:在这里 Message 开始持有 Handler
return queue.enqueueMessage(msg, uptimeMillis);
}

5. 总结

Handler 机制的持有关系是一个闭环

  1. Thread 通过 ThreadLocal 守住 Looper
  2. Looper 维护 MessageQueue
  3. HandlerMessageQueue 塞入 Message
  4. Message 反向持有 Handler

理解了这个闭环,就理解了 Android 异步消息处理的灵魂,也掌握了规避内存泄漏的钥匙。

从零开始写一个 ARouter - service 服务

  • ARouter
    • router-annotation 路由注解模块

      • src.main.java
        • com.alibaba.android.arouter
          • facade 提供注解和枚举的包
            • annotation 存放各种注解类的包
              • Autowired.java 自动注入的注解
              • Interceptor.java 拦截器的注解
              • Param.java(废弃) 参数注解: 被 Autowired 淘汰
              • Route.java 路由信息注解
            • enums 包含各种枚举类型的包
              • RouteType.java 路由类型的枚举
              • TypeKind.java 类型种类的枚举
            • model 包含模型类的包
              • RouteMeta.java 路由元信息的模型类
              • TypeWrapper.java 存储目标对象的泛型类型信息的类
    • arouter-api ARouter框架的API模块

      • src.main.java
        • com.alibaba.android.arouter
          • base 基础功能相关的包
            • UniqueKeyTreeMap.java 唯一键树形映射的类
          • core 核心功能相关的包
            • AutowiredLifecyleCallback.java(废弃) 自动注入生命周期回调的类
            • AutowiredServiceImpl.java 自动注入服务的实现类
            • InstrumentationHook.java(废弃) 仪表钩子的类
            • InterceptorServiceImpl.java 拦截器服务的实现类
            • LogisticsCenter.java 物流中心的类
            • Warehouse.java 仓库的类
          • exception 异常相关的包
            • HandlerException.java 处理异常的类
            • InitException.java 初始化异常的类
            • NoRouteFoundException.java 未找到路由的异常类
          • facade 提供各种服务和回调的包
            • callback 回调相关的包
              • InterceptorCallback.java 拦截器回调的接口
              • NavigationCallback.java 导航回调的接口
              • NoRouteFoundException.java 未找到路由的异常接口
          • service 服务相关的包
          • template 模板相关的包
            • IInterceptor.java 拦截器接口
            • IInterceptorGroup.java 拦截器分组接口
            • Ilogger.java 日志记录器接口
            • IPolicy.java 策略接口
            • IProvider.java 提供者接口
            • IProviderGroup.java 提供者分组接口
            • IRouteGroup.java 路由分组接口
            • IRouteRoot.java 路由根接口
            • Isyringe.java 注射器接口
            • Postcard.java 路由信息封装类
          • launcher 启动器: 包含一些用于启动ARouter框架的类和线程管理相关的类。
            • _Arouter.java ARouter框架的内部启动类,用于初始化ARouter。
            • Arouter.java ARouter框架的启动类,用于初始化ARouter。
          • thread (线程)包含了与线程管理相关的类。
            • CancelableCountDownLatch.java 可取消的倒计时计数器,用于线程同步。
            • DefaultPoolExecutor.java 默认的线程池执行器,用于执行异步任务。
            • DefaultThreadFactory.java 默认线程工厂,用于创建线程。
          • utils 工具类。
            • ClassUtils.java 用于操作类的实用工具类。
            • Consts.java 包含一些常量值的类。
            • DefaultLogger.java 默认的日志记录器类。
            • MapUtils.java 用于操作地图数据的实用工具类。
            • PackageUtils.java 用于操作包信息的实用工具类。
            • TextUtils.java 用于操作文本数据的实用工具类。
    • arouter-compiler

      • src.main.java
        • com.alibaba.android.arouter
          • compiler 编译相关的包
            • entity 实体类相关的包
              • RouteDoc.java 路由文档实体类
            • processor 处理器相关的包
              • AutowiredProcessor.java 自动注入处理器
              • BaseProcessor.java 基础处理器
              • InterceptorProcessor.java 拦截器处理器
              • RouteProcessor.java 路由处理器
            • utils 工具类相关的包
              • Consts.java 常量类
              • Logger.java 日志记录器类
              • TypeUtils.java 类型工具类

从零开始写一个 ARouter - template 模板

  • ARouter
    • router-annotation 路由注解模块

      • src.main.java
        • com.alibaba.android.arouter
          • facade 提供注解和枚举的包
            • annotation 存放各种注解类的包
              • Autowired.java 自动注入的注解
              • Interceptor.java 拦截器的注解
              • Param.java(废弃) 参数注解: 被 Autowired 淘汰
              • Route.java 路由信息注解
            • enums 包含各种枚举类型的包
              • RouteType.java 路由类型的枚举
              • TypeKind.java 类型种类的枚举
            • model 包含模型类的包
              • RouteMeta.java 路由元信息的模型类
              • TypeWrapper.java 存储目标对象的泛型类型信息的类
    • arouter-api ARouter框架的API模块

      • src.main.java
        • com.alibaba.android.arouter
          • base 基础功能相关的包
            • UniqueKeyTreeMap.java 唯一键树形映射的类
          • core 核心功能相关的包
            • AutowiredLifecyleCallback.java(废弃) 自动注入生命周期回调的类
            • AutowiredServiceImpl.java 自动注入服务的实现类
            • InstrumentationHook.java(废弃) 仪表钩子的类
            • InterceptorServiceImpl.java 拦截器服务的实现类
            • LogisticsCenter.java 物流中心的类
            • Warehouse.java 仓库的类
          • exception 异常相关的包
            • HandlerException.java 处理异常的类
            • InitException.java 初始化异常的类
            • NoRouteFoundException.java 未找到路由的异常类
          • facade 提供各种服务和回调的包
            • callback 回调相关的包
              • InterceptorCallback.java 拦截器回调的接口
              • NavigationCallback.java 导航回调的接口
              • NoRouteFoundException.java 未找到路由的异常接口
          • service 服务相关的包
            • AutowiredService.java 自动注入服务的接口
            • ClassLoaderService.java 类加载器服务的接口
            • DegradeService.java 降级服务的接口
            • InterceptorService.java 拦截器服务的接口
            • PathReplaceService.java 路径替换服务的接口
            • PretreatmentService.java 预处理服务的接口
            • SerializationService.java 序列化服务的接口
          • template 模板相关的包
          • launcher 启动器: 包含一些用于启动ARouter框架的类和线程管理相关的类。
            • _Arouter.java ARouter框架的内部启动类,用于初始化ARouter。
            • Arouter.java ARouter框架的启动类,用于初始化ARouter。
          • thread (线程)包含了与线程管理相关的类。
            • CancelableCountDownLatch.java 可取消的倒计时计数器,用于线程同步。
            • DefaultPoolExecutor.java 默认的线程池执行器,用于执行异步任务。
            • DefaultThreadFactory.java 默认线程工厂,用于创建线程。
          • utils 工具类。
            • ClassUtils.java 用于操作类的实用工具类。
            • Consts.java 包含一些常量值的类。
            • DefaultLogger.java 默认的日志记录器类。
            • MapUtils.java 用于操作地图数据的实用工具类。
            • PackageUtils.java 用于操作包信息的实用工具类。
            • TextUtils.java 用于操作文本数据的实用工具类。
    • arouter-compiler

      • src.main.java
        • com.alibaba.android.arouter
          • compiler 编译相关的包
            • entity 实体类相关的包
              • RouteDoc.java 路由文档实体类
            • processor 处理器相关的包
              • AutowiredProcessor.java 自动注入处理器
              • BaseProcessor.java 基础处理器
              • InterceptorProcessor.java 拦截器处理器
              • RouteProcessor.java 路由处理器
            • utils 工具类相关的包
              • Consts.java 常量类
              • Logger.java 日志记录器类
              • TypeUtils.java 类型工具类