14

VirtualAPP源码解析-Activity栈管理

 3 years ago
source link: https://zhuanlan.zhihu.com/p/162134693
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

VirtualAPP源码解析-Activity栈管理

58同城 Android工程师

之前的文章为大家大体介绍了VirtualAPP框架的大致原理及插件Activity是如何启动起来的,本篇文章主要为大家介绍插件Activity的栈管理是如果做到的。

v2-9c16e6315a7396fc64c5dcb0ed9c0a7f_720w.jpg

给大家画一个整体栈管理结构图,下面为大家进行讲解:

  1. VAPP在启动Activity时调用不是系统服务AMS而是调用的VAMS服务,而VMS当中存放了当前的所有的Task
  2. VMS根据Intent中的Flag和Activity的LaunchModle来确定是否需要创建新的任务栈还是使用之前的任务栈进行操作
  3. VMS确定之后会调用AMS并设置相应的Flag来启动VAPP中的Activity,做到相应的启动类型效果
  4. VAPP将Activity启动起来后,获取该Activity的taskid和该Activity信息传递给VAMS,通知VAMS更新对于的Task创建ActivityRecord

其实Activity的栈管理主要就是上述的四个步骤,下面我们从代码的角度进行详细说明

 <activity
            android:name=".client.stub.StubActivity$C0"
            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
            android:process=":p0"
            />

上篇文章我们已将了解到每个VAPP均在一个进程,并且都注册了一个标准启动模式的StubActivity。现在我们要做的就是用这一个标准启动模式的Activity去模拟四种LaunchModle启动效果和与Intent Flag配合在一起的效果。如果要我们去做的话,我们会想到用Intent Flag之前去模拟四种启动模式效果,然而只用Intetn Flag是无法做到的,如SingleInstance效果等。所以如果我们自己维护一个Activity栈结构和系统栈结构建立映射关系是不是就可以了呢?没错VA就是这样做的。

如果我们启动一个SingleInstance模式的Activity,我们先查找一下在我们维护的栈里有没有对应亲和度的Task包含该Activity如果包含将对应的taskid切换到前台,如何不包含直接创建新的Task启动Activity。

ActivityStack启动Acitivty方法源码解析

int startActivityLocked(int userId, Intent intent, ActivityInfo info, IBinder resultTo, Bundle options,
                            String resultWho, int requestCode) {
        /**
         * VAMS与AMS同步Activity栈信息
         */
        optimizeTasksLocked();

        Intent destIntent;
        ActivityRecord sourceRecord = findActivityByToken(userId, resultTo);
        /**
         * 跳转来源对应的任务栈
         */
        TaskRecord sourceTask = sourceRecord != null ? sourceRecord.task : null;
        /**
         * 默认使用来源Activity对应的任务栈
         */
        ReuseTarget reuseTarget = ReuseTarget.CURRENT;
        /**
         * 对目标Task不进行操作
         */
        ClearTarget clearTarget = ClearTarget.NOTHING;

        boolean clearTop = containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
        boolean clearTask = containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);

        if (intent.getComponent() == null) {
            intent.setComponent(new ComponentName(info.packageName, info.name));
        }

        /**
         * 启动模式是SingleInstance则需要放到新的任务栈中
         */
        if (sourceRecord != null && sourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        if (clearTop) {
            removeFlags(intent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
            clearTarget = ClearTarget.TOP;
        }

        if (clearTask) {
            /**
             * 是否清空Task FLAG_ACTIVITY_CLEAR_TASK必须与FLAG_ACTIVITY_NEW_TASK联合使用才能生效
             */
            if (containFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK)) {
                clearTarget = ClearTarget.TASK;
            } else {
                removeFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);
            }
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            switch (info.documentLaunchMode) {
                /**
                 * 系统会搜索基本 Intent 的 ComponentName 和数据 URI 与启动 Intent 的这些内容相匹配的任务。
                 * 如果发现此类任务,系统会将其清除,并在根 Activity 收到对 onNewIntent(android.content.Intent)
                 * 的调用时自行重启。如果未发现此类任务,系统会创建新任务。
                 */
                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                    clearTarget = ClearTarget.TASK;
                    reuseTarget = ReuseTarget.DOCUMENT;
                    break;
                /**
                 * 	Activity 为文档创建新任务,即便文档已经打开。这与同时设置 FLAG_ACTIVITY_NEW_DOCUMENT
                 * 	和 FLAG_ACTIVITY_MULTIPLE_TASK 标记的效果相同。
                 */
                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                    reuseTarget = ReuseTarget.MULTIPLE;
                    break;
            }
        }
        boolean singleTop = false;
        switch (info.launchMode) {
            case LAUNCH_SINGLE_TOP: {
                singleTop = true;
                if (containFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK)) {
                    reuseTarget = containFlags(intent, Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
                            ? ReuseTarget.MULTIPLE
                            : ReuseTarget.AFFINITY;
                }
            }
            break;
            case LAUNCH_SINGLE_TASK: {
                clearTop = false;
                clearTarget = ClearTarget.TOP;
                reuseTarget = containFlags(intent, Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
                        ? ReuseTarget.MULTIPLE
                        : ReuseTarget.AFFINITY;
            }
            break;
            case LAUNCH_SINGLE_INSTANCE: {
                clearTop = false;
                clearTarget = ClearTarget.TOP;
                reuseTarget = ReuseTarget.AFFINITY;
            }
            break;
            default: {
                if (containFlags(intent, Intent.FLAG_ACTIVITY_SINGLE_TOP)) {
                    singleTop = true;
                }
            }
            break;
        }

        if (clearTarget == ClearTarget.NOTHING) {
            if (containFlags(intent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)) {
                clearTarget = ClearTarget.SPEC_ACTIVITY;
            }
        }

        if (sourceTask == null && reuseTarget == ReuseTarget.CURRENT) {
            reuseTarget = ReuseTarget.AFFINITY;
        }

        String affinity = ComponentUtils.getTaskAffinity(info);
        TaskRecord reuseTask = null;
        switch (reuseTarget) {
            /**
             * 使用亲和度对应的任务栈
             */
            case AFFINITY: 
                reuseTask = findTaskByAffinityLocked(userId, affinity);
                break;
            /**
             * 如果任务栈栈底为该Activity则使用对应的任务栈
             */
            case DOCUMENT:
                reuseTask = findTaskByIntentLocked(userId, intent);
                break;
            /**
             * 使用跳转来源Activity对应的任务栈
             */
            case CURRENT:
                reuseTask = sourceTask;
                break;
            /**
             * 创建新的任务栈
             */
            default:
                break;
        }
        boolean taskMarked = false;
        if (reuseTask == null) {
            /**
             * 创建新的任务栈启动Activity
             */
            startActivityInNewTaskLocked(userId, intent, info, options);
        } else {
            boolean delivered = false;
            /**
             * 将目标Task移到前台
             */
            mAM.moveTaskToFront(reuseTask.taskId, 0);
            /**
             * 是否将Task移到前台就可以了
             */
            boolean startTaskToFront = !clearTask && !clearTop && ComponentUtils.isSameIntent(intent, reuseTask.taskRoot);

            if (clearTarget.deliverIntent || singleTop) {
                /**
                 * 将需要finish的Activity进行标记
                 */
                taskMarked = markTaskByClearTarget(reuseTask, clearTarget, intent.getComponent());
                ActivityRecord topRecord = topActivityInTask(reuseTask);
                if (clearTop && !singleTop && topRecord != null && taskMarked) {
                    topRecord.marked = true;
                }
                // Target activity is on top
                if (topRecord != null && !topRecord.marked && topRecord.component.equals(intent.getComponent())) {
                    /**
                     * 触发目标Activity的onNewIntent方法
                     */
                    deliverNewIntentLocked(sourceRecord, topRecord, intent);
                    delivered = true;
                }
            }
            /**
             * 将标记的Activity finish掉
             */
            if (taskMarked) {
                synchronized (mHistory) {
                    scheduleFinishMarkedActivityLocked();
                }
            }
            if (!startTaskToFront) {
                if (!delivered) {
                    destIntent = startActivityProcess(userId, sourceRecord, intent, info);
                    if (destIntent != null) {
                        /**
                         * 在目标task中启动Activity
                         */
                        startActivityFromSourceTask(reuseTask, destIntent, info, resultWho, requestCode, options);
                    }
                }
            }
        }

        return 0;
    }

https://www.jianshu.com/p/329a9eba3a79


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK