当前位置:首页 > 安卓源码 > 技术博客 >

Android 源码分析 Activity的启动模式

时间:2019-05-13 22:24 来源:互联网 作者:源码搜藏 浏览: 收藏 挑错 推荐 打印

一直想抽空针对AMS进行源码分析,无奈一方面因为很忙,另外AMS很复杂,涉及的知识点也比较多,今天利用五一假期对AMS的一个方面,Activity的启动模式进行源码分析,这里面包括了ActivityRecord,TaskRecord,ActivityStack等概念,写这篇博客之前,我也百度了
一直想抽空针对AMS进行源码分析,无奈一方面因为很忙,另外AMS很复杂,涉及的知识点也比较多,今天利用五一假期对AMS的一个方面,Activity的启动模式进行源码分析,这里面包括了ActivityRecord,TaskRecord,ActivityStack等概念,写这篇博客之前,我也百度了不少朋友的启动模式介绍和分析,有些讲的不清楚,少数从源码角度分析了,但是都看的非常麻烦,很难理解,我也一直在想,如何更好地阅读Android源码或者写关于源码分析的博客,我想了好久,目前个人觉得,写好源码博客,千万不能贴几大段源码上去,然后加点注释,这个效果很不好,一是很难有调理针对性的看,另外读者读起来也非常费劲。
 
本篇针对启动模式提了几个问题,一定要有针对性的问题去阅读源码,这样才能更加深刻理解其中的机制,本篇关于启动模式的几个问题如下:
 
1、如果被启动的Activity的模式是SingleTop,会在栈内重新创建该实例吗?如果不会,是什么情形,会又是什么情形?
 
2、如果被启动的Activity的模式是SingleTask,会重新创建栈吗?默认情况会还是不会?不会重新创建栈的话,会如何调用?如果会重新创建栈,又是在什么样的情形?
 
3、singleInstance的启动模式如何做到栈内唯一?
 
4、如果startActivity的intent设置了FLAG_ACTIVITY_NEW_TASK,一定会重新创栈吗?
 
5、如果singleTop的模式,设置了taskAffinity不一致,会重新创栈吗?如果要重新创建栈,要设置什么?
 
请读者也阅读下面源码之前,也思考一下这几个问题。
 
好,下面进行源码分析模式,Activity的启动模式相关逻辑的入口在ActivityStarter.java类中的 startActivityUnchecked方法
 
 private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
      
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor);
 
        computeLaunchingTaskFlags();
 
        computeSourceStack();
 
        mIntent.setFlags(mLaunchFlags);
 
        mReusedActivity = getReusableIntentActivity();
 
        final int preferredLaunchStackId =
                (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
 
        if (mReusedActivity != null) {
          
            if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
                    (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                mSupervisor.showLockTaskToast();
                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
 
            if (mStartActivity.task == null) {
                mStartActivity.task = mReusedActivity.task;
            }
            if (mReusedActivity.task.intent == null) {
                // This task was started because of movement of the activity based on affinity...
                // Now that we are actually launching it, we can assign the base intent.
                mReusedActivity.task.setIntent(mStartActivity);
            }
 
            // This code path leads to delivering a new intent, we want to make sure we schedule it
            // as the first operation, in case the activity will be resumed as a result of later
            // operations.
            if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || mLaunchSingleInstance || mLaunchSingleTask) {
                // In this situation we want to remove all activities from the task up to the one
                // being started. In most cases this means we are resetting the task to its initial
                // state.
                final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                        mStartActivity, mLaunchFlags);
                if (top != null) {
                    if (top.frontOfTask) {
                        // Activity aliases may mean we use different intents for the top activity,
                        // so make sure the task now has the identity of the new intent.
                        top.task.setIntent(mStartActivity);
                    }
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                            mStartActivity.launchedFromPackage);
                }
            }
 
            sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
 
            mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
 
            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don't need to start a new activity, and the client said not to do anything
                // if that is the case, so this is it!  And for paranoia, make sure we have
                // correctly resumed the top activity.
                resumeTargetStackIfNeeded();
                return START_RETURN_INTENT_TO_CALLER;
            }
            setTaskFromIntentActivity(mReusedActivity);
 
            if (!mAddingToTask && mReuseTask == null) {
                // We didn't do anything...  but it was needed (a.k.a., client don't use that
                // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
                resumeTargetStackIfNeeded();
                return START_TASK_TO_FRONT;
            }
        }
 
        if (mStartActivity.packageName == null) {
            if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
                mStartActivity.resultTo.task.stack.sendActivityResultLocked(
                        -1, mStartActivity.resultTo, mStartActivity.resultWho,
                        mStartActivity.requestCode, RESULT_CANCELED, null);
            }
            ActivityOptions.abort(mOptions);
            return START_CLASS_NOT_FOUND;
        }
 
        // If the activity being launched is the same as the one currently at the top, then
        // we need to check if it should only be launched once.
        final ActivityStack topStack = mSupervisor.mFocusedStack;
        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        if (dontStart) {
            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
            // For paranoia, make sure we have correctly resumed the top activity.
            topStack.mLastPausedActivity = null;
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ActivityOptions.abort(mOptions);
            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don't need to start a new activity, and the client said not to do
                // anything if that is the case, so this is it!
                return START_RETURN_INTENT_TO_CALLER;
            }
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
 
            // Don't use mStartActivity.task to show the toast. We're not starting a new activity
            // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
            mSupervisor.handleNonResizableTaskIfNeeded(
                    top.task, preferredLaunchStackId, topStack.mStackId);
 
            return START_DELIVERED_TO_TOP;
        }
 
        boolean newTask = false;
        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                ? mSourceRecord.task : null;
 
        // Should this be considered a new task?
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            setTaskFromReuseOrCreateNewTask(taskToAffiliate);
 
            if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            if (!mMovedOtherTask) {
                // If stack id is specified in activity options, usually it means that activity is
                // launched not from currently focused stack (e.g. from SysUI or from shell) - in
                // that case we check the target stack.
                updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
                        preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
            }
        } else if (mSourceRecord != null) {
            if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
 
            final int result = setTaskFromSourceRecord();
            if (result != START_SUCCESS) {
                return result;
            }
        } else if (mInTask != null) {
            // The caller is asking that the new activity be started in an explicit
            // task it has provided to us.
            if (mSupervisor.isLockTaskModeViolation(mInTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
 
            final int result = setTaskFromInTask();
            if (result != START_SUCCESS) {
                return result;
            }
        } else {
            // This not being started from an existing activity, and not part of a new task...
            // just put it in the top task, though these days this case should never happen.
            setTaskToCurrentTopOrCreateNewTask();
        }
        }
      
 
        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
     
        return START_SUCCESS;
    }
 
代码较多,我已经做了一部分删减,我先大概讲下方法,然后针对问题去分析
 
1、第5行 setInitialState 方法是设置变量初始化状态。
 
    private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
            boolean doResume, int startFlags, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
        reset();//  重置状态
        mStartActivity = r; // 被启动的Activity
        mIntent = r.intent; //启动的intent
        mSourceRecord = sourceRecord;//发起启动的Activity,比如A 启动B,A就是 sourceRecord
        mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP; //是否是singleTop启动模式,下同
        mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
        mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
     //  省略
 
2、第8行computeLaunchingTaskFlags 方法作用 是给不同的启动模式设置launchFlag,简言之,如果是singleTask或者singleInstance,就加上 FLAG_NEW_TASK的标签。
 
   private void computeLaunchingTaskFlags() {
        // If the caller is not coming from another activity, but has given us an explicit task into
        // which they would like us to launch the new activity, then let's see about doing that.
        if (mInTask == null) {
            if (mSourceRecord == null) {
                if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                }
            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            }
        }
    }
 
3、第10行 computeSourceStack() 主要作用是赋值ActivityStack。
 
4、第14行 mReusedActivity = getReusableIntentActivity();判断是否要创建一个新的实例加入栈,如果需要mReusedActivity 不为空,如果不需要,为空。
 
    /**
     * Decide whether the new activity should be inserted into an existing task. Returns null
     * if not or an ActivityRecord with the task into which the new activity should be added.
     */
    private ActivityRecord getReusableIntentActivity() {
       //标志位,如果为true,说明要放入已经存在的栈,可以看出,如果是设置了FLAG_ACTIVITY_NEW_TASK 而没有设置 FLAG_ACTIVITY_MULTIPLE_TASK,或者
       设置了singleTask以及singleInstance
        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || mLaunchSingleInstance || mLaunchSingleTask;
       // 重新检验
        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
        ActivityRecord intentActivity = null
        if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
            final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
            intentActivity = task != null ? task.getTopActivity() : null;
        } else if (putIntoExistingTask) {
            if (mLaunchSingleInstance) {
              //如果是 singleInstance,那么就找看看之前存在的该实例,找不到就为null
               intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
            } 
               else {
                // Otherwise find the best task to put the activity in.
                // 在栈中找出 符合要求的栈的topActivity,这里面也很复杂。
                intentActivity = mSupervisor.findTaskLocked(mStartActivity);
            }
        }
        return intentActivity;
    }
 
 
    /**
     * Returns the top activity in any existing task matching the given Intent in the input result.
     * Returns null if no such task is found.
     */
    void findTaskLocked(ActivityRecord target, FindTaskResult result) {
        Intent intent = target.intent;
        ActivityInfo info = target.info;
        ComponentName cls = intent.getComponent();
        if (info.targetActivity != null) {
            cls = new ComponentName(info.packageName, info.targetActivity);
        }
        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
        boolean isDocument = intent != null & intent.isDocument();
        // If documentData is non-null then it must match the existing task data.
        Uri documentData = isDocument ? intent.getData() : null;
 
        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            final TaskRecord task = mTaskHistory.get(taskNdx);
            
            final ActivityRecord r = task.getTopActivity();
            if (r == null || r.finishing || r.userId != userId ||
                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
                continue;
            }
          
            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
                    + taskIntent.getComponent().flattenToShortString()
                    + "/aff=" + r.task.rootAffinity + " to new cls="
                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
            // TODO Refactor to remove duplications. Check if logic can be simplified.
            if (taskIntent != null && taskIntent.getComponent() != null &&
                    taskIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
                        "For Intent " + intent + " bringing to top: " + r.intent);
                result.r = r;
                result.matchedByRootAffinity = false;
                break;
            } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                    affinityIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
                        "For Intent " + intent + " bringing to top: " + r.intent);
                result.r = r;
                result.matchedByRootAffinity = false;
                break;
            } else if (!isDocument && !taskIsDocument
                    && result.r == null && task.canMatchRootAffinity()) {
                if (task.rootAffinity.equals(target.taskAffinity)) {
                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
                    // It is possible for multiple tasks to have the same root affinity especially
                    // if they are in separate stacks. We save off this candidate, but keep looking
                    // to see if there is a better candidate.
                    result.r = r;
                    result.matchedByRootAffinity = true;
                }
            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
        }
    }
 
源码实在太多,我不想继续贴了,直接看问题说吧,最好自己也打开源码,对照起来读。
 
1、如果是singleTop的启动模式,computeLaunchingTaskFlags和它没有关系,这个方法没有针对这个模式设定flag,getReusableIntentActivity 得到的也是null,因为这个方法也不是主要针对这个模式(前提是启动的intent没有设置FLAG_ACTIVITY_NEW_TASK),
 
mReusedActivity 为null,我们看 final boolean dontStart = top != null && mStartActivity.resultTo == null 这一行之后,这里面就要分情况讨论了:
 
第一种情形:如果该Activity就是在栈顶,dontStart 为true,那么就调用其onNewIntent方法。
 
final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        if (dontStart) {
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
 
第二种情形:如果不在栈顶,那么 dontStart 为false,就会重新创建实例。
 
2、如果是singleTask模式,在第二个代码段,会将mLaunchFlags设置成FLAG_ACTIVITY_NEW_TASK模式,其效果等同于我们自己主动 加了这个flag,还是重点看下 getReusableIntentActivity方法,第三个代码段,
 
 boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || mLaunchSingleInstance || mLaunchSingleTask;
1
2
3
这个里面 putIntoExistingTask 为true。
走到下面第二个分支 ,调用 findTaskLocked方法。
 
else if (putIntoExistingTask) {
            if (mLaunchSingleInstance) {
        
               intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
            }  else {
                // Otherwise find the best task to put the activity in.
                
                intentActivity = mSupervisor.findTaskLocked(mStartActivity);
            }
        }
 
findTaskLocked 贴出来的代码非常长,我概括下,如果我们被启动的Activity没有显式的配置不一致的 taskAffinity,那么 调用到该方法的这里。
 
else if (!isDocument && !taskIsDocument
                    && result.r == null && task.canMatchRootAffinity()) {
                if (task.rootAffinity.equals(target.taskAffinity)) {
                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
                    // It is possible for multiple tasks to have the same root affinity especially
                    // if they are in separate stacks. We save off this candidate, but keep looking
                    // to see if there is a better candidate.
                    result.r = r;
                    result.matchedByRootAffinity = true;
                }
 
mReusedActivity 返回的是该栈中顶部的Activity,如果配置了不一样的taskAffinity,那么mReusedActivity就为null。
 
如果不为null,那么第一个代码段往下走,会走到这里。
 
 if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || mLaunchSingleInstance || mLaunchSingleTask) {
               //清除 该Activity在栈中上方的所有Activity
                final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                        mStartActivity, mLaunchFlags);
                if (top != null) {
                    if (top.frontOfTask) {
                        // Activity aliases may mean we use different intents for the top activity,
                        // so make sure the task now has the identity of the new intent.
                        top.task.setIntent(mStartActivity);
                    }
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
                   // 调用 onNewIntent方法
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                            mStartActivity.launchedFromPackage);
                }
            }
 
 
如果singleTask是一样的taskAffinity,会清除 其上方的所有activity,也就不会重新创栈。
 
因为 此时mAddingToTask 即使为false,但是走到这一段代码:
因为此时的topActivity就是 该模式的Activity,又满足了 mLaunchSingleTask模式,return掉了。
 
 final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        if (dontStart) {
            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
            // For paranoia, make sure we have correctly resumed the top activity.
            topStack.mLastPausedActivity = null;
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ActivityOptions.abort(mOptions);
            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don't need to start a new activity, and the client said not to do
                // anything if that is the case, so this is it!
                return START_RETURN_INTENT_TO_CALLER;
            }
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
 
            // Don't use mStartActivity.task to show the toast. We're not starting a new activity
            // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
            mSupervisor.handleNonResizableTaskIfNeeded(
                    top.task, preferredLaunchStackId, topStack.mStackId);
 
            return START_DELIVERED_TO_TOP;
        }
 
如果是不一样的taskAffinity,那么 mReusedActivity为null,走下面的代码段:
 
 boolean newTask = false;
        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                ? mSourceRecord.task : null;
        // Should this be considered a new task?
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            setTaskFromReuseOrCreateNewTask(taskToAffiliate)
 
mAddingToTask 默认为false, 因为singelTask的启动flag被设置成了 FLAG_ACTIVITY_NEW_TASK,所以 newTask 为true,调用创建新栈的逻辑。
 
好了,关于第二个问题也解答二楼。
 
3、如果是singleIntance模式,如果栈中已经存在该实例了,那么mReusedActivity不为空,这里有个注意点,系统针对这种模式,进行了单独处理,如果是 singleIntance,就去找该实例,然后赋值给 mReusedActivity,如果是其他模式,只是去找相同栈中的topActivity就可以了,一定要注意这一点,因为 singleIntance一定是栈中唯一的一个实例存在。
代码如下
 
  if (mLaunchSingleInstance) {
                // There can be one and only one instance of single instance activity in the
                // history, and it is always in its own unique task, so we do a special search.
               **intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);**
            } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
                // For the launch adjacent case we only want to put the activity in an existing
                // task if the activity already exists in the history.
                intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
                        !mLaunchSingleTask);
            } else {
                // Otherwise find the best task to put the activity in.
                intentActivity = mSupervisor.findTaskLocked(mStartActivity);
            }
 
如果 mReusedActivity不为空,说明之前启动过,会调用和singletask一样的流程,清除上面的activity(假设栈中其上方有其他实例)。
 
如果 mReusedActivity为空,还是会走到下面这个分支。
 
// Should this be considered a new task?
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            setTaskFromReuseOrCreateNewTask(taskToAffiliate);
 
            if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            if (!mMovedOtherTask) {
                // If stack id is specified in activity options, usually it means that activity is
                // launched not from currently focused stack (e.g. from SysUI or from shell) - in
                // that case we check the target stack.
                updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
                        preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
            }
 
4、如果仅仅设置了FLAG_ACTIVITY_NEW_TASK,那么并不会重新创建新栈,因为代码中还多了这个条件判断:
 
        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || mLaunchSingleInstance || mLaunchSingleTask;
1
2
3
可以看出来,即使 设置了这个如果缺少了 FLAG_ACTIVITY_MULTIPLE_TASK,
putIntoExistingTask 还是为true,那么还是会在原有的栈。除非加上 FLAG_ACTIVITY_MULTIPLE_TASK 的flag。
 
5、如果singleTop的模式设置了不同的taskAffinity,那么mReusedActivity就为null,导致mAddingToTask为false,如果加上 启动intent的flag为 FLAG_ACTIVITY_NEW_TASK的话,也是可以重新创建新栈的。
 
总结:
 
在不考虑主动设置启动的intent flag情况下:
 
1、standmode标准模式,启动一个新建一个实例,放入栈中。
2、singleTop,如果是栈顶部,复用,调用onNewIntent,如果不是,重新创建,放入栈顶。
3、singleTask,如果想要的栈已经存在,如果实例也在栈中存在,清除上方实例,如果不存在,创建该实例,如果想要的栈不存在,重新创建栈。
4、singleInstance,无论什么时候,都是栈内唯一,甚至全局唯一。
 
最后说实话,Android启动模式源码这一块写的真的非常非常的乱,是我读过相对很乱的代码,严重吐槽这一点。
--------------------- 
Android 源码分析 Activity的启动模式 转载https://www.codesocang.com/appboke/40006.html

技术博客阅读排行

最新文章