为什么Activity生命周期函数是运行在UI线程
Posted _houzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么Activity生命周期函数是运行在UI线程相关的知识,希望对你有一定的参考价值。
这是我自己给自己提的问题,或者说是Activity的生命周期函数是怎样运行在主线程的?下面简单分析一下,讨论的问题其实远远不止于这个问题。会涉及到进程的启动,Binder的线程池,ActivityThread中的消息处理。
进程开启
我们最开始接触android的时候,都知道主线程和非主线程区别,我们可以用Handler来将代码运行在主线程中。而主线程是如何开启的呢?在ActivityThread当中有个公有静态main方法,每次ActivityManagerService请求Zygote进程fork一个新的进程的时候,ActivityManagerService会同时发送一个指定新进程启动哪一个类的参数,ActivityManagerService指定的就是android.app.ActivityThread类。看看ActivityManagerService启动新进程的代码:
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
里面的entryPoint就是指定了zygote会启动的类。Process.start的第一个参数。可以看看Process.start函数,它会直接调用Process的startViaZygote私有静态方法,两个方法的参数是一致的:
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx
synchronized(Process.class)
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0)
argsForZygote.add("--enable-jni-logging");
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0)
argsForZygote.add("--enable-safemode");
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0)
argsForZygote.add("--enable-debugger");
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0)
argsForZygote.add("--enable-checkjni");
if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0)
argsForZygote.add("--enable-jit");
if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0)
argsForZygote.add("--generate-debug-info");
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0)
argsForZygote.add("--enable-assert");
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT)
argsForZygote.add("--mount-external-default");
else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ)
argsForZygote.add("--mount-external-read");
else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE)
argsForZygote.add("--mount-external-write");
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
//argsForZygote.add("--enable-debugger");
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0)
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++)
if (i != 0)
sb.append(',');
sb.append(gids[i]);
argsForZygote.add(sb.toString());
if (niceName != null)
argsForZygote.add("--nice-name=" + niceName);
if (seInfo != null)
argsForZygote.add("--seinfo=" + seInfo);
if (instructionSet != null)
argsForZygote.add("--instruction-set=" + instructionSet);
if (appDataDir != null)
argsForZygote.add("--app-data-dir=" + appDataDir);
argsForZygote.add(processClass);
if (extraArgs != null)
for (String arg : extraArgs)
argsForZygote.add(arg);
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
为了节省空间,我把一些空格给去掉了。这个方法就是将参数组装到argsForZygote当中,存到数组里面。而zygoteSendArgsAndGetResult方法则是通过socket将这些内容发送给Zygote进程:
/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
*
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx
try
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++)
String arg = args.get(i);
if (arg.indexOf('\\n') >= 0)
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
writer.write(arg);
writer.newLine();
writer.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = inputStream.readInt();
if (result.pid < 0)
throw new ZygoteStartFailedEx("fork() failed");
result.usingWrapper = inputStream.readBoolean();
return result;
catch (IOException ex)
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
上面就是跟zygote进行socket通信的部分,相信用过socket的看着都非常熟悉。关于zygote启动,并且ActivityManagerService如何建立通信的,想了解的更详细的可以看看老罗这两篇文章Android系统进程Zygote启动过程的源代码分析,[Android应用程序进程启动过程的源代码分析](http://blog.csdn.net/luoshengyang/article/details/6747696)。当然直接看源码是最合适的。
而zygote如何回应的?看看zygote部分启动一个新进程后的代码,zygote中fork之后,子进程会调用RuntimeInit.zygoteInit方法,所以直接从RuntimeInit.zygoteInit开始看。
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
nativeZygoteInit方法会调用ProcessState开启Binder线程池,供与Binder驱动通信使用。而applicationInit会调用invokeStaticMain方法调用ActivityManagerService传入的ActivityThread类的main方法。
其实整个流程就跟我们使用java命令运行程序是一样的。
main方法里面会设置主线程loop,然后调用Looper.loop()处理消息:
public static void main(String[] args)
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
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());
AndroidKeyStoreProvider.install();
// 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"));
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop(); //消息loop
throw new RuntimeException("Main thread loop unexpectedly exited");
Handler机制的使用
而ActivityManagerService使用binder机制(IApplicationThread)调用某个进程的四大组件时,ActivityThread部分,一开始是运行在Binder线程池的,然后通过Handler机制发送消息给主线程,运行相关内容,比如说启动Activity,IApplicationThread的方法scheduleLaunchActivity实现就如此:
private class ApplicationThread extends ApplicationThreadNative
@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);
sendMessage(H.LAUNCH_ACTIVITY, r);
最终消息处理的地方是在类ActivityThread.H(Handler的子类)的handleMessage方法中,ActivityThread.H的looper就是主线程的looper,这里就已经是运行在主线程了:
public void handleMessage(Message msg)
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
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);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
其他的四大组件也是一样的
以上是关于为什么Activity生命周期函数是运行在UI线程的主要内容,如果未能解决你的问题,请参考以下文章