在上一章节中,最后分析到了 Activity 的 startActivity 方法,从此方法开始继续向下分析:
public void startActivity(Intent intent, @Nullable Bundle options) {
// ... 这里省略了处理 Activity 恢复数据相关的内容
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// 请注意,我们希望通过此调用与可能已覆盖该方法的应用程序兼容。
startActivityForResult(intent, -1);
}
}
Activtiy 的 startActivity 方法的注释:
“
启动一个新的 Activity 。
您不会收到任何与 Activity 有关的信息。
此实现覆盖了基础版本,提供了有关 Activity 执行启动的相关信息。由于这些附加信息,不需要 Intent.FLAG_ACTIVITY_NEW_TASK 。
如果未指定,新的 Activity 将添加到调用者的任务栈中。如果没有找到给定 Intent 所指定的 Activity ,此方法将抛出 android.content.ActivityNotFoundException 。
Anyway,Activtiy 的 startActivity 最终还是通过 startActivityForResult 方法进行的:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
这个方法中,根据 mParent 是否存在,形成了两种逻辑:
-
mParent 不存在,通过 Instrumentation 的 execStartActivity 方法获取了一个 ActivityResult ,然后再通过 ActivityThread 的 sendActivityResult 方法将 ActivityResult 发送出去。 -
mParent 存在,调用 startActivityFromChild 方法启动 Activity 。
由此可以产生三个疑问:
-
mParent 是什么,哪来的? -
Instrumentation 的 execStartActivity 做了什么? -
startActivityFromChild 做了什么?
下面将一一探索这个三个问题的答案。
parent 的来源
parent 属性是一个 Activity 类型的对象,它有两个赋值的使用:
-
setParent 方法 -
attach 方法中的参数
setParent 没有被调用;而 attach 方法有两个调用来源:
-
ActivityThread#performLaunchActivity
“
Activity 启动的核心实现
-
Instrumentation#newActivity
“
执行 Activity 对象的实例化,此方法适用于单元测试,例如 android.test.ActivityUnitTestCase。
Instrumentation#execStartActivity
“
该方法用于执行应用程序发出的 startActivity 调用。默认的实现负责更新 Activity 的 Instrumentation.ActivityMonitor 对象,并将此调用分配给系统的 Activity Manager ;你可以通过覆盖这个类以监视应用程序启动 Activity ,并修改它在启动时的行为。
此方法返回一个 Instrumentation.ActivityResult 对象,您可以在应用程序调用此方法时,拦截该方法避免执行启动 Activity 的操作,但仍应该返回一个应用程序期待的返回值。为此,请重写此方法来捕获 start activity 的调用,以便它返回一个新的 ActivityResult 。其中包含您希望应用程序看到的结果,并且不要调用超类。请注意,仅当 requestCode >= 0 时,应用程序才会期待结果。
如果没有找到运行给定 Intent 的 Activity,此方法将抛出 ActivityNotFoundException。
从这个方法的注释中我们可以提取出几个关键信息:
-
该方法用于执行应用程序发出的 startActivity 调用。 -
可以覆盖这个类以监视应用程序启动 Activity 。
来看看这个方法的默认实现:
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
// ... 这里省略 mActivityMonitors 更新等逻辑
try {
// intent 信息准备
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
// AMS 调用 startActivity
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
// 检查结果
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
在这个方法中,最关键的一行代码就是 ActivityTaskManager.getService().startActivity(...)
。ActivityTaskManager 对应的系统服务是 ActivityTaskManagerService 。
Activity#startActivityFromChild
startActivityFromChild 方法已标记为弃用,建议使用 androidx.fragment.app.FragmentActivity#startActivityFromFragment(androidx.fragment.app.Fragment,Intent,int)
这个方法是 Activity 的子 Activity 调用 startActivity 或 startActivityForResult 时,会调用到此方法。
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, child, intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(mToken, child.mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
}
cancelInputsAndStartExitTransition(options);
}
这个方法也是调用了 mInstrumentation.execStartActivity(...)
。
原文始发于微信公众号(八千里路山与海):App启动流程【2】Activity 到 ActivityTaskManagerService 的调用流程
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/85056.html