您的位置:首页 > 教育 > 培训 > Activity的启动流程(AndroidU)

Activity的启动流程(AndroidU)

2024/10/6 1:46:26 来源:https://blog.csdn.net/zinjin_woxin/article/details/141499821  浏览:    关键词:Activity的启动流程(AndroidU)

启动有冷热温三种。

冷启动:从无到有走完整个启动流程。一般是应用第一次启动。

热启动:有应用进程无相关数据,需要重新加载,比如冻结。一般是从多任务进入。

温启动:有进程有数据。一般是退出后再次进入。

启动流程如下:

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方法。(应用启动的是第一个界面,应该没有接受者关注启动结果)
详细逻辑:
  1. 检查 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)启动另外一个活动的功能,它执行以下主要任务:

  1. 检查并处理可能存在的活动引用(referrer)。
  2. 检查并处理可能存在的活动监视器。
  3. 调整 Intent 对象,并准备启动活动。
  4. 调用底层的 ActivityTaskManager 服务启动活动。

这个方法在处理启动活动时结合了监视器匹配和阻塞机制,从而提供了安全且灵活的启动活动方式。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com