启动有冷热温三种。
冷启动:从无到有走完整个启动流程。一般是应用第一次启动。
热启动:有应用进程无相关数据,需要重新加载,比如冻结。一般是从多任务进入。
温启动:有进程有数据。一般是退出后再次进入。
启动流程如下:
1.启动准备
应用启动是从应用Activity的this.startActivity开始,调用父类Acitivity.startActivity.
xref: /frameworks/base/core/java/android/app/Activity.java
1.1Acitivity#startActivity.
这两个方法都是为了启动新的 Activity,但它们的差别在于第二个方法允许传入额外的启动选项。第一个方法是第二个方法的简化版本,默认将 options
传为 null
,以便于兼容性处理。
@Override
public void startActivity(Intent intent) {this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {getAutofillClientController().onStartActivity(intent, mIntent);if (options != null) {startActivityForResult(intent, -1, options);} else {// Note we want to go through this call for compatibility with// applications that may have overridden the method.startActivityForResult(intent, -1);}
}
Activity#startActvityForResult
这两个方法用于启动新的 Activity,并在之后等待它返回结果。第一个方法是第二个方法的简化版本,默认将 options
传为 null
。第二个方法通过更复杂的逻辑来处理启动,包括处理顶层 Activity 和子 Activity 的不同情况,并且可以传递更多的启动选项。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);
}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);} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {mParent.startActivityFromChild(this, intent, requestCode);}}
}
参数:
intent
:要启动的新 Activity 的意图(Intent 对象)。requestCode
:用于标识启动的 Activity 的请求码。这里是-1,表示不期待返回结果,不执行onActivityResult方法。(应用启动的是第一个界面,应该没有接受者关注启动结果)
详细逻辑:
- 检查
mParent
是否为null
:-
如果
mParent
为null
,表示这是一个顶层 Activity:- 将
options
参数进行处理,可能是为了适配或者转换选项。 - 通过
Instrumentation
类的execStartActivity
方法来启动新的 Activity,传递必要的参数,包括当前上下文、应用线程、启动 Token、Intent
、请求码和选项。 - 如果启动结果
ar
不为null
,则通过mMainThread
发送启动结果。正常启动的ar值是为null的,不用空时一般用作测试或启动失败。 - 如果请求码
requestCode
大于等于 0,设置mStartedActivity
为true
,这通常表示启动的 Activity 会返回结果,期间将当前的 Activity 保持隐藏状态。 - 调用
cancelInputsAndStartExitTransition
方法来取消输入并启动退出过渡动画。(本文分析的是应用启动,调用startActivityForResult重载时,传入为null,没有退出动画。可能从launcher启动时,上个界面即launcher不需要退出动画。应用内部启动调用这个方法的参数可能不为null,需要上个界面的动画)
- 将
-
如果
mParent
不为null
,表示这是一个子 Activity:- 根据
options
是否为null
,调用mParent
的相应方法startActivityFromChild
来启动子 Activity。传递必要的参数,包括当前的 Activity、Intent
、请求码以及选项。
- 根据
- 顶层Activity不依赖其他activty,可作为程序主入口。子Activity依赖父Activity,通过父activity管理和启动。例如:在一个电商应用中,一个主 Activity (如
CategoryActivity
) 可能启动一个子 Activity (如ProductDetailActivity
) 来显示一个特定类型商品的详细信息。
-
1.2Instrumentation#execStartActivity
Instrumentation主要负责调用跟踪Activity和Application的生命周期。execStartActivty有3个重载方法,根据参数类型及个数不同,分别是从Actvity启动Activity、从Fragment启动Activity、从特定用户上下文启动一个Activity。上面方法中传入的this为Activity,此处分析从Activity启动Activity流程。
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
参数解释
Context who
: 当前启动活动的上下文。IBinder contextThread
: 上下文的主线程。IBinder token
: 用于标识谁启动了活动,可以为null
。Activity target
: 执行启动操作的活动组件。Intent intent
: 用于启动活动的Intent
对象。int requestCode
: 请求结果的标识符;如果小于零表示调用者不期待结果。Bundle options
: 传递给新活动的选项
执行逻辑
声明主线程和处理引用者
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
- 获取主线程。
- 检查并获取
referrer
,如果target
不为null
,则调用target.onProvideReferrer()
。 - 如果
referrer
不为null
,将其放入Intent
的额外数据中。
检查活动监视器
if (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {final ActivityMonitor am = mActivityMonitors.get(i);ActivityResult result = null;if (am.ignoreMatchingSpecificIntents()) {if (options == null) {options = ActivityOptions.makeBasic().toBundle();}result = am.onStartActivity(who, intent, options);}if (result != null) {am.mHits++;return result;} else if (am.match(who, null, intent)) {am.mHits++;if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}
}
如果有活动监视器,则遍历这些监视器:
- 检查是否忽略特定
Intent
的匹配。- 如果是且
options
为null
,则创建基本的ActivityOptions
。 - 调用监视器的
onStartActivity
方法,并检查是否返回了ActivityResult
。 - 如果返回了
ActivityResult
,增加监视器命中计数并返回结果。 - 否则,检查监视器是否匹配当前的
Context
和Intent
。- 如果匹配且监视器是阻塞的,返回监视器的结果(如果
requestCode
大于等于 0);否则退出循环。
- 如果匹配且监视器是阻塞的,返回监视器的结果(如果
- 如果是且
启动活动
try {intent.migrateExtraStreamToClipData(who);intent.prepareToLeaveProcess(who);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);notifyStartActivityResult(result, options);checkStartActivityResult(result, intent);
} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);
}
- 调整
intent
中的ClipData
。 - 为即将离开进程做准备。
- 调用
ActivityTaskManager
服务的startActivity
方法启动活动。 - 通知启动结果,并进行检查。
- 捕获
RemoteException
并抛出运行时异常。
总结
这个方法提供了从活动(Activity
)启动另外一个活动的功能,它执行以下主要任务:
- 检查并处理可能存在的活动引用(
referrer
)。 - 检查并处理可能存在的活动监视器。
- 调整
Intent
对象,并准备启动活动。 - 调用底层的
ActivityTaskManager
服务启动活动。
这个方法在处理启动活动时结合了监视器匹配和阻塞机制,从而提供了安全且灵活的启动活动方式。