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 服务启动活动。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值