再遇Looper&构造ActivityClientRecord
上一篇文章分析到:app.thread.scheduleLaunchActivity会跨进程通知App进程启动Activity。thread是android.app.ActivityThread.ApplicationThread类型的实例。
继续分析android.app.ActivityThread.ApplicationThread#scheduleLaunchActivity:
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profileFile = profileName;
r.profileFd = profileFd;
r.autoStopProfiler = autoStopProfiler;
//系统信息相关内容,场景无关
updatePendingConfiguration(curConfig);
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
参数挺多的,都是用于构造ActivityClientRecord实例,前几篇文章讲过ActivityClientRecord是用来记录App进程侧的Activity的,我们之前使用过MainActivity的ActivityClientRecord,而这次构造的是属于TargetActivity的ActivityClientRecord。
private void queueOrSendMessage(int what, Object obj) {
//是不是有点眼熟
queueOrSendMessage(what, obj, 0, 0);
}
是的,之前在pause掉MainActivity的时候就是调用的它,往looper里面抛信息的。这里思考一个问题为什么要用looper去异步执行?而不是直接顺序同步执行?
稍微思考一下即可得到答案:Binder是同步调用的,也就是说执行到这AMS还在等待App进程执行完成呢,同样startActivity最初的调用处还在等待AMS执行完成呢,如果不用looper异步执行,那么系统进程会一直被挂在那里,这哪能行呢,AMS还要处理其他的startActivity或者其他的跨进程调用呢。
因此当系统进程通知App进程执行任务时,都是通过looper的方式来执行的。就好比一个母猪十个崽,奶就在那,已经告诉你吃奶了,爱吃不吃,还有剩下九个崽要管呢。
android.app.ActivityThread.H#handleMessage:
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
...
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
...
} break;
...
}
onCreate、onStart、onResume的准备工作
继续分析android.app.ActivityThread#getPackageInfoNoCheck:
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true);
}
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
synchronized (mPackages) {
WeakReference<LoadedApk> ref;
//先从内存缓存里取Apk信息
if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
//取不到的话创建一个,并且放在内存缓存里,下次可以直接用
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
...
packageInfo =
new LoadedApk(this, aInfo, compatInfo, this, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
}
具体如何执行不再分析,该函数就是获得了Apk的信息。赋值给了r.packageInfo。
android.app.ActivityThread#handleLaunchActivity:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward);
...
} else {
...
}
}
onCreate、onStart的调用
函数代码比较长,实际上场景相关的只有两行,分别是performLaunchActivity和handleResumeActivity的调用。
先分析android.app.ActivityThread#performLaunchActivity。
函数比较长(难道google编码规范,没有限制函数行数吗,100多行了),分两段进行分析,第一段:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
//若没有拿到Apk信息,再次尝试取拿,不走这,之前已经拿到了Apk信息,上文分析过
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
//当前场景的组件名不会为null。若是null,还会尝试向PMS查找
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
...
Activity activity = null;
try {
//拿到ClassLoader
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//利用ClassLoader和组件名(TargetActivity类全称),实例化TargetActivity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//不知道干啥用的,场景无关
StrictMode.incrementExpectedActivityCount(activity.getClass());
//一些赋值
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
//第一段结束
...
}
第一段核心内容:创建Activity实例。
android.app.Instrumentation#newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent):
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
创建过程很简单。
继续分析系第二段:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
//第二段开始
try {
//拿到App进程对应的Application对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
//设置Activity相关的Context内容
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
...
//把一些信息设置个Activity,其中Activity的”身份证”mToken就是在这里设置的
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
...
activity.mCalled = false;
//调用onCreate
mInstrumentation.callActivityOnCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
//把Activity记录给ActivityClientRecord
r.activity = activity;
//还没有resume,先设置成true
r.stopped = true;
//onCreate调用后,马上调用onStart
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
...
}
//还没有resume,先设置成true
r.paused = true;
//把ActivityClientRecord记录下来。前面文章中使用过mActivities查找MainActivity的ActivityClientRecord
mActivities.put(r.token, r);
}
...
return activity;
}
这函数主要干了一下几件事:
- 创建Activity实例
- 给Activity设置好Context
- 设置attach一些Activity需要的信息
- 调用Activity的onCreate方法
- 调用Activity的onStart方法
- 把Activity实例记录下来,方便后续查找
这里再简单分析下onCreate的调用android.app.Instrumentation#callActivityOnCreate:
public void callActivityOnCreate(Activity activity, Bundle icicle) {
...
activity.performCreate(icicle);
...
}
final void performCreate(Bundle icicle) {
onCreate(icicle);
...
//Fragment的onActivityCreated分发
mFragments.dispatchActivityCreated();
}
调用和onPause类似,也是用过Instrumentation进行调用,也会验证是否调用了super方法。不再赘述。
在onCreate里会调用setContentView来设置布局。
android.app.Activity#setContentView(int):
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
getWindow()返回的是com.android.internal.policy.impl.PhoneWindow类型的。
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 构造DecorView
installDecor();
} else {
mContentParent.removeAllViews();
}
// 根据xml创建View树
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
setContentView构造DecorView和View树,这里不是本文重点,不再分析。
onResume的调用
继续回到handleLaunchActivity中,分析:
android.app.ActivityThread#handleResumeActivity:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
...
// 执行onResume
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
...
}
//记录Window、DecorView等。最后把View加进Window(使用ViewRootImpl进行add)
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
//暂时设置成INVISIBLE
decor.setVisibility(View.INVISIBLE);
ViewManager wm = 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);
}
} else if (!willBeVisible) {
...
}
...
// 里面会把DecorView设置成VISIBLE
r.activity.makeVisible();
}
代码比较长,但场景有用的就两步:
- 调用onResume函数
- 记录Window、DecorView等到ActivityClientRecord里,并把View添加进Window
下面我们继续分析android.app.ActivityThread#performResumeActivity:
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide) {
//根据token拿ActivityClientRecord,老套路了
ActivityClientRecord r = mActivities.get(token);
...
//显而易见,走这儿
if (r != null && !r.activity.mFinished) {
//clearHide传入的是true,设置了一些变量,一时半会儿用不到
if (clearHide) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
try {
...
//里面用调用onResume
r.activity.performResume();
...
//这俩在调用onCreate的时候都设置成true了,现在已经resume了,设置成false
r.paused = false;
r.stopped = false;
r.state = null;
} catch (Exception e) {
...
}
}
return r;
}
过程很简单,注释里已经能描述清楚了。主要是调用onResume和设置状态值。
继续看下android.app.Activity#performResume:
final void performResume() {
//里面会调用onRestart声明和周期函数
performRestart();
...
mCalled = false;
//依然是老套路,通过Instrumentation调用onResume,并且必须调用super方法
mInstrumentation.callActivityOnResume(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onResume()");
}
mCalled = false;
//Fragement分发resume
mFragments.dispatchResume();
...
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPostResume()");
}
}
onResume和onPause、onCreate不同的是,它会尝试调用一下onRestart。
android.app.Activity#performRestart:
final void performRestart() {
mFragments.noteStateNotSaved();
//很显然这里是false,不会走进去。只有当退出Activity的时候才是true,才会调用onRestart声明周期函数
if (mStopped) {
....
performStart();
}
}
这里也印证了启动Activity的声明周期函数不包括onRestart。
android.app.Instrumentation#callActivityOnResume:
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
activity.onResume();
...
}
这里就是onResume的调用了。
任务完成
我们知道周期函数是在looper里执行的,跨进程的调用实际上早已返回到了AMS中。当Handler的LAUNCH_ACTIVITY消息发后,这时AMS的主要任务就已经完成了。而App进程侧完成了LAUNCH_ACTIVITY消息里的内容后,TargetActivity就算真正被启动了。
总结
App进程侧的任务执行都通过Looper来执行的,不能一直阻塞着系统进程。
- App进程侧记录了构造ActivityClientRecord,并且通过android.app.Activity#mToken映射好,存下来,以备以后使用。
- 调用了onCreate、onStart
- 调用onResume。调用前检查了是否需要调用onRestart,发现不用调用。