主线程的消息处理
Android中主线程的程序入口是ActivityThread类的main方法,main方法是一个静态方法,在main方法中会创建ActivityThread的实例对象,会创建主线程的Looper并开启Looper循环,main方法的源码如下:
public static void main(String[] args) {
.................//省略部分代码
//创建主线程的Looper
Looper.prepareMainLooper();
//创建ActivityThread的实例,注意ActivityThread不是线程类
ActivityThread thread = new ActivityThread();
thread.attach(false);
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循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
以Activity的启动过程(只说跟消息传递相关的部分)为例进行说明消息传递过程,ActivityThread有两个比较重要的内部类ApplicationThread 、H,下面是这两个类的部分源码:
private class ApplicationThread extends IApplicationThread.Stub {
..............................//省略代码
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
//方法内部用H发送一个Handler消息到ActivityThread中
sendMessage(H.LAUNCH_ACTIVITY, r);
}
..............................//省略代码
}
private class H extends Handler {
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 void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
..............................//省略代码
}
由源码可知ApplicationThread 继承了 IApplicationThread.Stub,所以ApplicationThread 是一个可以跨进程通信的Binder类,在Activity的启动过程中用于和AMS进行进程间通信。H继承了Handler ,H是ActivityThread中用来进行消息通信的Handler。
Activity的启动需要通过AMS,AMS处理完启动请求后会回调给ApplicationThread,由于AMS是在一个单独的进程中,所以上述过程是进程间通信的一个过程,ApplicationThread接收到回调后,会调用自身的scheduleLaunchActivity方法向ActivityThread的Handler(H)中发送一条消息(该消息的标志是H.LAUNCH_ACTIVITY,消息体包含了被启动的Activity的信息),然后主线程的Looper从消息队列中取出该消息,交由H进行分发处理,最终会在ActivityThread的H中的handleMessage方法里匹配出标志是H.LAUNCH_ACTIVITY的消息进行处理(启动Activity)。这样主线程的整个消息处理过程就结束了。Activity的生命周期方法调用、Service的启动停止等都跟上述处理过程一样。
主线程的Looper循环为什么不会导致ANR
在主线程中进行耗时操作,会导致程序无响应(ANR),那么主线程的Looper死循环为什么不会导致ANR呢,那就要先说一下ANR出现的原因是什么,导致ANR的原因一般有两种:
- 当前的事件一直没有处理(主线程在处理上一个事件,还没有轮到)。
- 正在处理当前事件,但是当前事件比较耗时,长时间不能响应结果。
从上面两个导致ANR的原因可以知道,产生ANR的根本原因是阻塞了主线程的整个消息循环,而不是阻塞了主线程,消息循环中的某一个消息的处理比较耗时以至于长时间对用户操作没有响应,让Looper也长时间不能取下条消息进行处理,整个循环系统就卡住了。而Looper的无限循环是消息循环畅通的一个保证,它不会卡住整个消息循环系统,所以不会导致ANR。