从源码解析Android异步消息处理机制(三)

从源码解析Android异步消息处理机制(三)


前言:本篇纯属个人学习笔记,故摘录《Android开发艺术探索》大量语句,特此声明



问题:主线程默认可以使用Handler的原因?
Android的主线程是ActivityThread(Android.app.ActivityThread类),我们可以看它的main方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    public static void main(String[] args) {
SamplingProfilerIntegration.start();

// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);

Environment.initForCurrentUser();

// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());

Security.addProvider(new AndroidKeyStoreProvider());

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

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

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();
thread.attach(false);

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

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}

在main方法中通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()来开启主线程的消息循环。当然ActivityThread还需要一个Handler来和消息队列进行交换,从源码我们看出sMainThreadHandler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程。

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 final int LAUNCH_ACTIVITY         = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;

public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
switch (msg.what) {
...
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
...
}
public final void scheduleExit() {
queueOrSendMessage(H.EXIT_APPLICATION, null);
}

而在学习Looper.loop()时,我们提过,只有调用了Looper.quit(),loop()才会跳出循环,对于主程序的消息循环,我一直没有找到源码是在哪里调用了scheduleExit()(如果读者知道,恳请赐教…)
对于主线程的消息循环还涉及了ApplicationThread和AMS的相关知识,由于笔者学的尚浅,所以此处留空以待学完再来补充……

HandlerThread

我们知道在子线程之间通信可以使用Handler+Thread来完成(需操作Looper:调用Looper.prepare()和Looper.loop()),对于这个需求Google官方已经封装了一个类——HandlerThread
HandlerThread的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;

...
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
...
}

可以看到HandlerThread继承了Thread,它是一种可以使用Handler的Thread,它在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop来开启消息循环。它和普通线程的区别就是多了一个Looper,这是子线程特有的Looper,用来做消息的取出和处理。由于HandlerThread的run方法是个死循环,因此当不需要使用HandlerThread时,可以通过它的quit()或quitSafely()来终止线程的执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}

public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}

最后撸一个示例:

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
private HandlerThread mHandlerThread;
......
mHandlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
//创建Handler,使用mHandlerThread.getLooper()生成Looper
final Handler handler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
System.out.println("收到消息");
}
};
//然后再新建一个子线程来发送消息
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);//模拟耗时操作
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//最后一定不要忘了在onDestroy释放,避免内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}