深入剖解Android四大组件(七)——Activity启动的4个阶段
在Activity的启动流程中,共有4个阶段,下面将一一道来。
1.第一阶段——启动信息翻译以及服务调用
这一阶段的工作主要是在应用程序本地完成的,主要为启动Activity做一些参数上的准备,然后服务的代理将这些参数转发到服务,开始Activity启动的流程,如下图:
2.第二阶段——Activity的相关处理
到了这个阶段,工作就已经由ActivityManagerService处理了。在此阶段,它将完成对ActivityStack及应用程序进程的相关处理,如下图:
在以上流程中,我们完成了对Activity任务,Activity记录和窗口的处理等。接下来,由startPausingLock()方法来开始真正的启动流程,所以这里将其称为预处理流程。这里,它抛出了一个PAUSE_TIMEOUT_MSG消息到处理程序,由处理程序启动activityPaused()方法开始真正的启动流程。
至此,应用程序就被添加到启动历史列表(mHistory)并生成相应的栈信息。但要注意的是,这时应用程序还没有自己的进程,所以需要做的下一件事情就是通知孵化进程为我们的应用程序孵化一个进程。
3.第三阶段——处理应用程序进程
创建并启动应用程序的入口是Process的start()方法,该方法的原型如下所示:
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid,int gid,int[] gids,
int debugFlags,int targetSdkVersion,
String[] zygoteArgs){
try{
return startViazygote(processClass,niceName,uid,gid,gids,debugFlags,targetSdkVersion,zygoteArgs);
}catch(ZygoteStartFailedEx ex){
Log.e(LOG_TAG,"Starting VM process through Zygote failed");
throw new RuntimeException("Starting VM process through Zygote failed",ex);
}
}
通过上面的代码可以看到,使用该方法时需要提供一个processClass参数。当应用程序进程创建完毕后,需要调用processClass类的main()方法继续完成未完成的工作,这里未完成的工作是指继续完成启动Activity的工作。
在ActivityManagerService()中,是这样调用start()方法的:
private final void startProcessLocked(ProcessRecord app,String hostingType,String hostingNameStr){
..........
Process.ProcessStartResult startResult=Process.start("android.app.ActivityThread",app.processName,uid,gid,gids,debugFlags,app.info.targetSdkVersion,null);
.........
}
这里start()方法的第一个参数为android.app.ActivityThread,也就是说,进程创建完成以后,将调用android.app.ActivityThread类的main()静态方法完成启动Activity的剩余流程。
接下来,Process的startViaZygote()方法将处理这些输入参数,将其变成一个参数数组argsForZygote。下面的代码片段展示了这个过程,这里我们需要关注一些标志以及进程名字的处理:
private static ProcessStartResult startViaZygeote(......)throws ZygoteStartFailedEx{
Synchronized(Process.class){
......
//如果启动了VM安全模式标志(android:vmSafeMode设置为true)
if((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE)!=0){
argsForZygote.add("--enable-safemode");
}
//如果启动了可调试标志(android:debuggable设置为true)
if((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER)!=0){
argsForZygote.add("--enable-debugger");
}
........
argsForZygote.add("--target-sdk-version="+targetSdkVersion);
........
if(niceName!=null){
//niceName一般为需要启动的应用程序的包名
argsForZygote.add("--nice-name="+niceName);
}
argsForZygote.add(processClass);
return zygoteSendArgsAndGetResult(argForZygote);
}
}
完成参数处理后,就需要使用一个socket连接来与孵化进程通信,这通过zygoteSendArgAndGetResult()方法来完成,该方法的代码如下所示:
private static ProcessStartResult
zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx{
openZygoteSocketIfNeeded();//打开与孵化进程连接的socket
.......
int sz=arg.size();
for(int i=0;i<sz;i++){
Stirng arg=args.get(i);
........
sZygoteWriter.write(arg);
sZygoteWriter,newLine();
}
sZygoteWriter.flush();
........
return result;
}
这里ZygoteConnection将会检测到这些输入,它的runOnce()方法将会读取这些参数并生成一个应用程序进程,然后调用android.app.ActivityThread类的main()方法完成这些任务,相关代码如下:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller{
........
try{
args=readArgumentList();
}catch(IOException ex){
.........
}
.......
pid=Zygote.forkAndSpecialize(parsedArgs.uid,parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,rlimits);
.......
if(pid==0){
handleChildProc(parsedArgs,descriptors,childPipeFd,newStderr);
return true;
}
.......
}
在上述代码中,readArgumentList()方法用于从socket中读取参数信息并提供runOnce()方法处理。等到进程生成完毕以后,调用handleChildProc()方法回到指定类的main()方法:
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors,FileDescriptor pipeFd,
PrintStream newStdrr)
throws ZygoteInit.MethodAndArgsCaller{
........
try{
ZygoteInit.invokeStaticMain(cloader,className,mainArgs);
}cathc(RuntimeException ex){
logAndPrintError(newStderr,"Error starting.",ex);
}
.....
}
在上面的代码中,最后调用的是ZygoteInit的invokeStaticMain()方法,这个方法负责调用ActivityThread的maiin()方法以完成剩余的工作。
至此,孵化进程就创建了一个应用程序的进程。
4.第四阶段——显示应用程序并处理当前当前显示的Activity的生命周期
在这个阶段,流程回到了ActivityThread的main()方法中,其主要工作是显示目标Activity并且调整Launcher应用程序中Activity的生命周期,将Launcher的生命周期置为paused,其核心代码如下:
public static void main(String[] args){
........
ActivityThread thread=new ActivityThread();
thread.attach(false);
.........
}
在上述代码中,attach()方法的输入参数为false,表示当前不是系统处理,它将启动另一个分支处理这个请求,具体代码如下所示:
private void attach(boolean system){
........
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr=ActivityManagerNative.getDefault();
try{
mgr.attachApplication(mAppThread);
}catch(RemoteException ex){
......
}
.......
}
在这里,我们调用ActivityManagerService的attachApplication()方法来实现Activity的调度工作。这时,ActivityThread的scheduleLaunchActivity()方法将被调用。scheduleLaunchActivity()方法的定义如下:
public final void scheduleLaunchActivity(......){
ActivityClientRecord r=new ActivityClientRecord();
.......
queueOrSendMessage(H.LAUNCH_ACTIVITY,r);
}
在上述代码中,queueOrSendMessage(H.LAUNCH_ACTIVITY,r)方法实际上发送了一个LAUNCH_ACTIVITY消息,这样做将会启动handleLaunchActivity()方法。当此方法执行完毕后,目标Activity将会显示出来,而Launcher将会被隐藏到它的后面处于paused状态。现在我们来看看handleLaunchActivity()方法的流程,如下图:
在这里,performLaunchActivity()方法负责实例化并创建需要显示的Activity,并回调Activity的部分生命周期函数。performLaunchActivity()方法的部分代码如下所示:
private Activity performLaunchActivity(ActivityClientRecord r,
Intent customIntent){
.......
//创建Activity实例
java.lang.ClassLoader cl=r.packageInfo.getClassLoader();
activity=mInstrumentation.newActivity(cl,component.getClassName(),r.intent);
.......
//创建应用程序
Application app=r.packageInfo.makeApplication(false,mInstrumentation);
.......
//创建应用程序上下文
ContextImpl appContext=new ContextImpl();
appContext.init(r.packageInfo,r.token,this);
appContext.setOuterContext(activity);
//设置应用程序标题
CharSequence title=r.activityInfo.loadLabel(appContext.getPackageManager());
//设置应用程序的配置
Configuration config=new Configuration(mCompatConfiguration);
//附加到Activity
activity.attach(appContext,this,getInstrumentation(),r.token,
r.ident,app,r.intent,r.activityInfo,title,r.parent,
r.embeddedID,r.lastNonConfigurationInstances,config);
.........
//如果我们设置了android:theme属性,那么这里需要设置该Activity的风格
if(theme!=0){
activity.setTheme(theme);
}
//调用Activity的onCreate()回调接口
//一般来说,这里应用程序会使用setContentView()方法设置界面的UI
mInstrumentation.callActivityOnCreate(activity,r.state);
........
//调用Activity的onStart()回调接口
//这时Activity处于started状态
activity.performStart();
........
//如果之前曾经保存了Activity状态
//这里需要调用onRestoreInstanceState()方法恢复之前保存的状态
if(r.state!=null){
mInstarumentation.callActivityOnRestoreInstanceState(activity,r.state);
}
.......
//回调Activity的onPostCraete()方法
mInstrumentation.callActivityOnPostCreate(activity,r.state);
........
return activity;
}
完成这个函数时,Activity处于生命周期的started状态。
接下来,handleResumeActivity()方法将负责显示这个Activity,具体代码如下:
final void handleResumeActivity(IBinder token,boolean clearHide,
boolean isForward){
ActivityClientRecord r=performResumeActivity(token,clearHide):
........
//显示Activity视图
if(r.window==null && !a.mFinished && willBeVisible){
r.window=r.activity.getWindow();
View decor=r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager vm=a.getWindowManager();
WindowManager.LayoutParams l=r.window.getAttributes();
a.mDecor=decor;
l.type=WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |=forwardBit;
if(a.mVisibleFromClient){
a.mWindowAdded=true;
wm.addView(decor,l);
}
}
........
}
在上述代码中,performResumeActivity()方法负责回调Activity的一些生命周期回调方法以完成界面显示,具体代码如下:
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide){
ActivityClientRecord r=mActivities.get(token);
.......
r.activity.performResume();
........
return r;
}
其中Activity的performResume()方法的代码如下:
final void performResume(){
........
mInstrumentation.callActivityOnResume(this);
.......
}
在Instrumentation的callActivityOnResume()方法中,将会回调activity的onResume()方法,具体如下列代码所示:
public void callActivityOnResume(Activity activity){
activity.mResumed=true;
activity.onResume();
........
}
当完成了handleResumeActivity()方法后,Activity就处于可见生命周期中(Activity的resumed状态)。
在完成这4个阶段之后,我们就看到了目标Activity,原先的Activity被此Activity覆盖。
要注意的是,当我们退出这个Activity的时候,孵化进程为此应用程序孵化出来的进程依然存在,除非Activity因为异常而被强行关闭或者使用其他手段(比如DDMS或者KILL等工具)强行杀掉进程。因此,当我们重新启动这个应用程序的时候,就不会再次为此应用程序创建进程。相关代码如下所示:
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume,boolean checkConfig){
ProcessRecord app=mService.getProcessRecordLocked(r.processName,
r.info.application.uid);
........
if(app!=null && app.thread!=null){
try{
app.addPackage(r.info.packageName);
realStartActivityLocked(r,app,andResume,checkConfig);
return;
}cathc(RemoteException e){
Slog.w(TAG,"Exception when starting activity"
+r.intent.getComponent().flattenToShortString(),e);
}
}
mService.startProcessLocked(r.processName,r.info.applicationInfo,true,0,"activity",r.intent.getComponent(),false);
}
本博文中,我们用了一个简单的例子描述了Android启动Activity过程。此外,Android框架还为开发者提供了一系列控制应用程序,Activity行为(比如android:launchMode等)以及应用程序进程性质的标志(比如android:debuggable等)。在使用这些标志时,Android的ActivityManagerService将会按照不同的规则调度Activity。
- 1楼lhc2207221755昨天 20:53
- 已推
- Re: liyuanjinglyj昨天 21:04
- 回复lhc2207221755n谢谢