概述
一.概述
对着老罗的博客和源码自己梳理了一遍Activity的启动过程,为了方便记忆就将这个过程整理写了下来,整个启动过程涉及到的类主要有Activity,ActivityManagerService,ActivityStack, PackageManagerService,ActivityThread和ApplicationThread.涉及到的进程一般是有2个,如果是启动另外一个应用的acitiviy就有3个进程,第一个就是我们当前应用所在的进程,第二个就是ActivityManagerService所在的进程,如果有第3个就是要启动的activity所在的进程.所以整个启动过程就涉及到了Binder的通信,其中上面说的ActivityManagerService,PackageManagerService和ApplicationThread都是Binder的子类这3个就是负责整个启动过程中的进程通信的.
二.启动过程分析
整个过程其实可以理解成2个过程,第一过程就是在他们的应用进程中封装intent将要启动的activity的信息传入到ActivityManagerService中,第二个过程就是在ActivityManagerService通过PackageManagerService来验证intent信息,通过ActivityStack来管理任务栈和存储activity,通过ActivityThread的消息队列来实际操作activity的创建和生命周期的创建.
下面就先从要启动activity所在的进程开始分析
1.Activity.startActivity->startActivityForResult->mInstrumentation.execStartActivity->ActivityManagerNative.getDefault().startActivity
2.ActivitymanagerService.startActivity
从这一步开始就进入到了ActivitymanagerService所在的进程了,这ActivitymanagerService的startActivity方法中其实是通过调用ActivityStack.startActivityMayWait方法来处理逻辑.
3.ActivityStack.startActivityMayWait
这个方法首先调用PackageManagerService的resolveIntent方法来解析intent找到这个intent代表的activity信息,
然后在调用startActivityLocked方法.
4.ActivityStack.startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified)
首先调用ActivityStack.isInAnyStackLocked方法其实就在ActivityStack的mActivityDisplays容器中查找要启动的activity是否存在于任意一个任务栈中.
在判断从PackageManagerService中获取到的acitiviyinfo是否为null,如果为null就表示要启动的acitiviy是没有在任何的清单文件中声明过的,就会抛出异常,否则就会通过new activityrecord 创建即将要启动的Activity的相关信息,并保存在r变量中,然后在调用startActivityUncheckedLocked
5.ActivityStack .startActivityUncheckedLocked
在这个里面会获取要启动的activity的启动模式,然后根据启动模式和要启动的activity的任务栈是否存在等信息来判断要不要启动新的任务栈,然后在进入到 startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options)中
6.ActivityStack .startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options)
这个方法就判断是否要切换新的界面,要切换就调用到resumeTopActivitiesLocked方法.
7.ActivityStack .resumeTopActivitiesLocked
它首先看要启动的Activity是否就是当前处于Resumed状态的Activity,如果是的话,那就什么都不用做,直接返回就可以了;否则再看一下系统当前是否休眠状态,如果是的话,再看看要启动的Activity是否就是当前处于堆栈顶端的Activity,如果是的话,也是什么都不用做。
上面两个条件都不满足,因此,在继续往下执行之前,首先要把当处于Resumed状态的Activity推入Paused状态,然后才可以启动新的Activity。但是在将当前这个Resumed状态的Activity推入Paused状态之前,首先要看一下当前是否有Activity正在进入Pausing状态,如果有的话,当前这个Resumed状态的Activity就要稍后才能进入Paused状态了,这样就保证了所有需要进入Paused状态的Activity串行处理。调用startPausingLocked将activity进入到Paused状态
8.ActivityStack .startPausingLocked
函数首先把mResumedActivity保存在本地变量prev中。mResumedActivity就是当前处于resume状态的activity,因此,这里把当前resueme状态进程中的ApplicationThread对象取出来,通过它来通知这个Activity它要进入Paused状态了。通过调用这个ApplicationThread对象的schedulePauseActivity来通知这个activity进入Paused状态.因为startPausingLocked是在acitiviymanagerservice进程的,而当前resume状态的activity是在我们的应用进程的,所以想要从acitiviymanagerservice进程让我们应用进程的activity进入pause状态就需要用到Binder通信,而这里完成这个通信的Binder就ApplicationThread.这个ApplicationThread就是一个Binder子类定义在ActivityThread类中.就了为了帮助ActivityThread完成进程间通信的.
- ActivityThread . ApplicationThread . schedulePauseActivity
1. public final class ActivityThread {
2.
3.
......
4.
5.
private final class ApplicationThread extends ApplicationThreadNative {
6.
7.
......
8.
9.
public final void schedulePauseActivity(IBinder token, boolean finished,
10.
boolean userLeaving, int configChanges) {
11.
queueOrSendMessage(
12.
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
13.
token,
14.
(userLeaving ? 1 : 0),
15.
configChanges);
16.
}
17.
18.
}
19.
20. }
其实到这一步 就是到了当前处于resume状态的activity的ActivityThread也就是主线程中来了,然后schedulePauseActivity中就是通过handler将消息发送到主线程的消息队列中去了,在看下主线程的handlerH 的handmessage方法:
1.
public void handleMessage(Message msg) {
2.
switch (msg.what) {
3.
case PAUSE_ACTIVITY:
//
4.
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
5.
maybeSnapshot();
6.
break;
7.
......
8.
9.
}
如果是pause_activity就调用handlePauseActivity方法.
10.ActivityThread.handlePauseActivity
最终还是调用mInstrumentation.callActivityOnPause(r.activity)来让当前activity进入到pause状态.
然后在调用ActivityManagerNative.getDefault().activityPaused(token);告诉activitymanager这个Activity已经进入Paused状态了,ActivityManagerService现在可以完成未竟的事情,即启动新的Activity了
11.activityStack.activityPausedLocked
这个方法会继续调用completePauseLocked方法来保存pauseactivity的信息,然后调用resumeTopActivitiesLocked()
12.activityStack.resumeTopActivitiesLocked
在这个方法中会拿到我们将要启动的activityrecord,然调用startSpecificActivityLocked(r),这里就将要启动的activirecord当参数传入
13.activityStack.startSpecificActivityLocked
1. public class ActivityStack {
2.
3.
......
4.
5.
private final void startSpecificActivityLocked(ActivityRecord r,
6.
boolean andResume, boolean checkConfig) {
7.
通过activityrecord的进程名和uid来获取进程 ,如果用户没有在xml指定默认就是包名
8.
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
9.
r.info.applicationInfo.uid);
10.
11.
......
12.
如果拿到了进程,就直接调用realStartActivityLocked
13.
if (app != null && app.thread != null) {
14.
try {
15.
realStartActivityLocked(r, app, andResume, checkConfig);
16.
return;
17.
} catch (RemoteException e) {
18.
......
19.
}
20.
}
21.
如果没有拿到进程,就先通过进程名创建进程
22.
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
23.
"activity", r.intent.getComponent(), false);
24.
}
25.
26.
27.
......
28.
29. }
这里就有2种情况了,如果是一个进程的第一个acitiviy也就进程还没有创建的情况就会调用ams的startProcessLocked方法先去创建进程,如果是进程已经存在的就会调用activityStack.realStartActivityLocked直接去创建acitiviy.因为创建进程完也是要创建activity的所以我们这里先去看一下ams.startProcessLocked方法.
- ActivityManagerService .startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting))
在这个方法中会再次再次检查是否已经有以process + uid命名的进程存在,如果不存在就会创建一个ProcessRecord,在调用startProcessLocked(ProcessRecord app,
1. String hostingType, String hostingNameStr)方法.
14.ActivityManagerService .startProcessLocked(ProcessRecord app,
1. String hostingType, String hostingNameStr),在这个方法中会调用Process.start来创建一个新的进程,实际上进程的创建还要交给Zygote进程来创建的,新的进程会导入android.app.ActivityThread类,并且执行它的main函数.
15.ActivityThread .main
1. public static final void main(String[] args) {
2.
3.
.......
4.
5.
ActivityThread thread = new ActivityThread();
6.
thread.attach(false);
7.
8.
......
9.
10.
Looper.loop();
11.
12.
.......
13.
14.
thread.detach();
15.
16.
......
17.
}
这个函数在进程中创建一个ActivityThread实例,然后调用它的attach函数,接着就进入消息循环了,直到最后进程退出,所以一个进程都会有一个ActivityThread实例表示主线程.函数attach最终调用了ActivityManagerService的远程接口ActivityManagerProxy的attachApplication函数,传入的参数是mAppThread,这是一个ApplicationThread类型的Binder对象
16.ActivityManagerService.attachApplication
这里最终是调用attachApplicationLocked(IApplicationThread thread,int pid)函数来处理,thread和pid都是新进程传过来的
17.ActivityManagerService.attachApplicationLocked
这个方法会通过pid拿到我们之前创建的activirecord,并且将thread等信息设置给activityrecord,然后在调用activityStack.realStartActivityLocked.
18.activityStack.realStartActivityLocked
这里最终通过app.thread进入到ApplicationThreadProxy的scheduleLaunchActivity函数中,注意,这里的第二个参数r,是一个ActivityRecord类型的Binder对象,用来作来这个Activity的token值,这里就进入新的acitiviy所在的进程然后创建对应的acitiviy了,通信就是通过这个thread来通信的
19.ActivityThread .ApplicationThread .scheduleLaunchActivity
到了这里其实还是要通过handler将要创建activity的消息发送到消息队列中,所以下面就是进入到H的handmessage中.最终调用ActivityThread .handleLaunchActivity
20.ActivityThread .handleLaunchActivity
1. private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
2.
......
3.
创建acitiviy,并且回调onCreate方法
4.
Activity a = performLaunchActivity(r, customIntent);
5.
6.
if (a != null) {
7.
r.createdConfig = new Configuration(mConfiguration);
8.
Bundle oldState = r.state;
i.
在回调onResume方法,让acitiviy进入到onResume状态
9.
handleResumeActivity(r.token, false, r.isForward);
10.
11.
......
12.
} else {
13.
......
14.
}
15.
}
21.最终是调用performLaunchActivity来创建activity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//得到目标activity的ComponentName对象
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
//从package中拿到目标类的类加载器
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//通过 mInstrumentation.newActivity创建acitiviy,实际就是通过类加载器反射创建
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
} catch (Exception e) {
...
}
try {
//如果该activity的进程application不存在就通过mInstrumentation的newApplication创建一个新的application,并且调用onCreate方法,如果已经存在了就直接返回,在应用中进程是用application来表示的
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
//创建一个新的Context
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
调用activity的attach方法,赋值context,Instrumentation对象
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
//调用activity的oncreate方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
}
return activity;
}
三.总结
1 就是将intent信息送入到activitymanagerservie中,这里涉及到了跨进程通信
3-6 就是负责校验要启动的acitiviy是否有在清单文件中注册过,没有就抛出异常,有就根据启动模式和flag等信息创建出对应的ActivityRecord准备启动
7-11 这个几个步骤就在准备启动新的activity之前先将当前处于resume状态的activity进入到pause状态,这里首先要从activitymanagerservice进程将要进入pause状态的信息发送到应用进程,等acitiviy进入到pause状态以后又要从应用进程将进入pause状态完成的信息发送到activitymanagerservice进程中
12-13 这2步就拿到要启动的activityrecord,并且通过activityrecord的进程名和uid来获取进程,如果进程不存在就创建进程,要存在就直接创建acitiviy
14-17 这几步就创建一个新的进程的过程,进程的创建都是通过Zygote进程来创建的,然后每一个进程都会创建一activitythread实例
18-21 这几部就是启动新的activity的过程,它是从acitiviymanagerservie进程及nag要启动的信息发送到新的acitiviy所在的进程的,然后通过消息队列来完成acitiviy的创建.
activityt的创建和生命周期的调用都是通过mInstrumentation来统一管理的.
最后
以上就是怡然电话为你收集整理的Activity启动过程分析的全部内容,希望文章能够帮你解决Activity启动过程分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复