activity启动流程分析

先来个大体流程图:
在这里插入图片描述
我们一般调用startActivity这个API来启动一个新的activity。实际上差不多所有的APP基本是由launcher 调用这个接口拉起来的。所以我们只要从Activity.java这个类跟踪看其实现过程就可以。

1.startActivity

    @Override
    public void startActivity(Intent intent) {
   
   
        this.startActivity(intent, null);
    }
        @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
   
   
        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);
        }
    }

如上代码所示,实际上调用的是startActivityForResult这个接口

2.startActivityForResult

    /**
     * Same as calling {@link #startActivityForResult(Intent, int, Bundle)}
     * with no options.
     *
     * @param intent The intent to start.
     * @param requestCode If >= 0, this code will be returned in
     *                    onActivityResult() when the activity exits.
     *
     * @throws android.content.ActivityNotFoundException
     *
     * @see #startActivity
     */
    public void startActivityForResult(@RequiresPermission 
    Intent intent, int requestCode) {
   
   
        startActivityForResult(intent, requestCode, null);
    }
在这里 可以仔细看下上面的注释说明,如果requestCode这个参数大于等于0,那么activity起来后,会在onActivityResult()这个接口里面返回。所以
如果我们需要返回值,则直接调startActivityForResult接口。因为startActivity传入的是-1
  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) {
   
   
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
   
   
        ……

这里做的事比较少,就2步
1.如果传入的options是空值,那么会获取调用都的options.但有个前提就是调用者的动画类型是ANIM_SCENE_TRANSITION
2.调用Instrumentation类提供的execStartActivity接口

3.execStartActivity

   public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
   
   
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        //这个是用来表明身份的,表示调用者是谁。如果有需要则要
        //重写onProvideReferrer这个接口(调用者)
        if (referrer != null) {
   
   
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        //mActivityMonitors应该为null,我搜遍所有代码,也没找到有
        //谁调用了addMonitor接口
        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()) {
   
   
                        result = am.onStartActivity(intent);
                    }
                    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;
                    }
                }
            }
        }
        try {
   
   
        //这个是针对intent的一些特殊的action增加一些flag和操作
            intent.migrateExtraStreamToClipData();
        //如果intent的包名和调用者的包者不一样,那么调用者这边就
        //需要做一些准备动作
            intent.prepareToLeaveProcess(who);
          //调用AMS接口进行启动activity的流程
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), 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;
    }

这个API主要就是AMS的startActivity的接口,继续进入下步流程。这里需要注意下传递的参数

4.startActivity

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
   
   
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

这块就是新增加了一个参数,uid.如果系统支持多用户那么 uid就是IPC那边获取的。不支持多 用户那就是系统用户

5.startActivityAsUser

    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
   
   
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

这个函数,前面检查uid。实际上,根本代码实现并没有作什么操作。主要就是后面调用ActivityStarter类的接口继续流程,注意传入的参数

7.startActivityMayWait

  final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
   
   
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors()) {
   
   
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        mSupervisor.mActivityMetricsLogger.notifyActivityLaunching();
        boolean componentSpecified = intent.getComponent() != null;

        // Save a copy in case ephemeral needs it
        final Intent ephemeralIntent = new Intent(intent);
        // Don't modify the client's object!
        intent = new Intent(intent);
        if (componentSpecified
                && intent.getData() != null
                && Intent.ACTION_VIEW.equals(intent.getAction())
                && mService.getPackageManagerInternalLocked()
                        .isInstantAppInstallerComponent(intent.getComponent())) {
   
   
            // intercept intents targeted directly to the ephemeral installer the
            // ephemeral installer should never be started with a raw URL; instead
            // adjust the intent so it looks like a "normal" instant app launch
            intent.setComponent(null /*component*/);
            componentSpecified = false;
        }
		//根据intent和userid,查找所有应用。根据其Manifest的配置
		//找到我们所需要的activity,这块是调用的PMS服务
        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
        if (rInfo == null) {
   
   
            UserInfo userInfo = mSupervisor.getUserInfo(userId);
            if (userInfo != null && userInfo.isManagedProfile()) {
   
   
                // Special case for managed profiles, if attempting to launch non-cryto aware
                // app in a locked managed profile from an unlocked parent allow it to resolve
                // as user will be sent via confirm credentials to unlock the profile.
                UserManager userManager = UserManager.get(mService.mContext);
                boolean profileLockedAndParentUnlockingOrUnlocked = false;
                long token = Binder.clearCallingIdentity();
                try {
   
   
                    UserInfo parent = userManager.getProfileParent(userId);
                    profileLockedAndParentUnlockingOrUnlocked = (parent != null)
                            && userManager.isUserUnlockingOrUnlocked(parent.id)
                            && !userManager.isUserUnlockingOrUnlocked(userId);
                } finally {
   
   
                    Binder.restoreCallingIdentity(token);
                }
                
### 活动安排问题中贪婪算法与动态规划的结合 对于活动安排问题,采用贪婪算法和动态规划相结合的方式可以在某些特定场景下获得更优的结果。贪婪算法倾向于每次选择局部最优解以期望达到全局最优解;而动态规划则通过构建子问题之间的关系表来逐步解决问题。 #### 贪婪算法在活动安排中的应用 考虑一组需要按时间顺序排列并执行的任务列表,在给定每项任务开始时间和结束时间的情况下,目标是从这组活动中挑选尽可能多的不重叠活动参与[^3]。贪婪方法会选择最早完成的下一个可用活动作为当前最佳选项直到无法再选为止。 #### 动态规划的作用 当面对更加复杂的约束条件时——比如不同活动之间存在依赖关系或是有额外的成本关联,则单纯依靠贪婪可能不足以找到真正的最优方案。此时引入动态规划的思想就显得尤为重要了。可以通过定义状态转移方程来记录到达某一点的最佳路径以及累积价值,进而推导出整个序列的最大收益。 #### 组合使用示例 下面给出一个简单的例子说明如何将两者结合起来处理带有权重(即重要程度)的活动选择: 假设有一个数组`activities[]`表示各个活动的信息,其中每个元素是一个三元组`(start_time, end_time, weight)`分别代表起始时刻、终止时刻及对应的权值大小。我们的目的是找出总权重最大的非冲突子集合。 ```python def weighted_activity_selection(activities): # 首先按照end time升序排序 activities.sort(key=lambda x: x[1]) n = len(activities) dp = [0] * (n + 1) for i in range(1, n + 1): s_i, e_i, w_i = activities[i - 1] j = binary_search_last_non_conflict(activities[:i], s_i) # 找到最后一个不会与此活动相撞的位置 dp[i] = max(dp[i-1], dp[j]+w_i) return dp[n] def binary_search_last_non_conflict(sorted_activities, start_time_of_current_activity): lo, hi = 0, len(sorted_activities)-1 while lo <= hi: mid = (lo + hi)//2 _, end_mid, _ = sorted_activities[mid] if end_mid <= start_time_of_current_activity: last_compatible_index = mid+1 lo = mid + 1 else: hi = mid - 1 return last_compatible_index # 测试用例 test_cases = [ [(1, 2, 5), (3, 4, 8), (0, 6, 7)], [(1, 2, 1), (3, 4, 3), (0, 6, 5)] ] for case in test_cases: print(f"Max Weight Sum of Non-overlapping Activities is {weighted_activity_selection(case)}") ``` 这段程序首先对输入的数据进行了预处理,使得后续查找最近兼容活动变得容易起来。接着利用了一个辅助函数来进行二分查找操作,最后则是核心部分——基于前向指针更新最大加权和的过程。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bruk_spp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值