Activity LaunchMode

2025-06-30

Activity LaunchMode

Activity一共有五种LaunchMode,分别是:

  • Standard:标准模式,每启动一个Activity都会创建一个新的实例
  • SingleTop: 栈顶复用模式,如果栈顶存在Activity实例,则复用该实例并回调onNewIntent方法
  • SingleTask:栈内复用模式,如果栈内存在一个Activity实例,则复用该实例并置于栈顶,回调onNewIntent方法
  • SingleInstance:单实例模式,此模式的Activity只能单独位于一个任务栈中,再次启动Activity时,均不会再创建Activity的实例,并回调onNewIntent方法
  • SingleInstancePerTask:全局共用一个Activity,不同于SingleInstance模式,该模式允许其栈内运行某些其他实例

LaunchMode 测试

实例

MainActivity

public class MainActivity extends Activity implements View.OnClickListener {

    Button mainButton;

    Button subButton;
    TextView view;

    private static int count = 0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.main_activity);
        count += 1;
        mainButton = (Button) this.findViewById(R.id.main_button);
        subButton = (Button) this.findViewById(R.id.sub_button);
        mainButton.setOnClickListener(this);
        subButton.setOnClickListener(this);
        view = this.findViewById(R.id.count_text);
        view.setText("mainActivity "+ count);
    }

    @Override
    public void onClick(View v) {
        if(v.equals(mainButton)){
            Intent intent = new Intent(getBaseContext(),MainActivity.class);
            startActivity(intent);
        }else{
            Intent intent = new Intent(getBaseContext(),SubActivity.class);
            startActivity(intent);
        }
    }
}

SubActivity

public class MainActivity extends Activity implements View.OnClickListener {

    ... // same with main

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ... // same with main
        view.setText("subActivity "+ count);
    }

    ... // same with main
}

standard模式测试

manifest文件中,配置MainActivitySubActivitylaunchModestandard

...
<activity android:name=".MainActivity" android:exported="true" android:launchMode="standard" android:process=".mainProcess">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="standard" android:process=".mainProcess"/>
...
</manifest>

启动项目后,MainActivity显示:

first launch

调用一次startActivity开启一个新的MainActivity显示:

second launch

此时,通过dumpsys activity activities查看任务栈,显示:

second stack

,可以看到,创建了两个不一样的MainActivity实例

singleTop模式测试

修改manifest文件,设置LaunchModesingleTop

...
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:process=".mainProcess">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleTop" android:process=".mainProcess"/>
...
</manifest>

启动项目后,MainActivity显示:

first launch

再启动一个MainActivity,显示:

second launch

dumpsys activity activities显示:

first stack

可以看到,由于MainActivity位于栈顶,此时会复用MainActivity

启动一次SubActivity后再启动MainActivity显示:

third launch

dumpsys activity activities显示:

second stack

,可以看到,由于MainActivity不在栈顶,会创建一个新的MainActivity实例并放入栈顶

singleTask模式测试

修改AndroidMainfest.xml文件:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleTask"/>

启动一次MainActivity,显示:

first launch

启动一次SubActivitydumpsys activity activities显示:

first stack

再次启动MainActivity,显示:

second launch

dumpsys activity activities显示:

second stack

,可以看到,MainActivity被复用了,同时栈中元素被删除并将MainActivity放入了栈顶

再次启动SubActivity,显示:

third launch

,可以看到,由于SubActivity记录被销毁,会重新创建一个SubActivity实例

singleInstance模式测试

修改AndroidMainfest.xml文件:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleInstance">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleInstance"/>

启动MainActivitySubActivitydumpsys activity activities显示:

first stack

,可以看到,为每个实例单独开启了一个进程

再次启动MainActivity,显示:

second launch

再次启动SubActivity,显示:

third launch

,可以看到,MainActivitySubActivity都被复用了

修改AndroidManifest.xml

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleInstance" android:process=".mainProcess">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleInstance" android:process=".mainProcess"/>

,通过dumpsys activity activities,可以看到:

second stack

,即使指定了相同的process,仍然会运行在不同的task中

singleInstancePerTask测试

修改AndroidMainfest.xml文件:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleInstancePerTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" />

运行一次MainActivitySubActivitydumpsys显示:

first stack

,可以看到,SubActivity可以和MainActivity运行在一个task中,如果修改singleInstance的manifest如下:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleInstance">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" />

查看其dumpsys显示: second stack

,可以发现,SubActivity不可以与MainActivity运行在一个task中

再次启动SubActivity,观察dumpsys显示: third stack ,可以发现,和singleTask相同,同一个栈中的其他记录被删除了,并且将MainActivity放入了栈顶

修改AndroidMainfest.xml文件:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleInstancePerTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleInstancePerTask"/>

此时启动MainActivitySubActivitydumpsys显示: forth stack

,由于MainActivitySubActivity都是singleInstancePerTask,于是在同一个task中,只能存在他们其中的一个,于是两者运行在了不同的task中

修改manifest文件为:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTask" android:process=".mainProcess">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleInstancePerTask" android:process=".mainProcess"/>

启动MainActivitySubActivity,可以看到:

fifth stack

,即使指定了同一个task,MainActivitySubActivity还是运行在了不同的task中

但是修改manifest文件为:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleInstancePerTask" android:process=".mainProcess">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name=".SubActivity" android:exported="true" android:launchMode="singleTask" android:process=".mainProcess"/>

后,则通过dumpsys可以看到: sixth stack ,两个Activity运行在了同一个task中

结合Activity启动流程看LaunchMode

开始启动Activity

在调用startActivity方法时,会调用到ActivityStarterexecuteRequest方法:

private int executeRequest(Request request) {
    ...
    ActivityInfo aInfo = request.activityInfo;
    ...
    final int launchMode = aInfo != null ? aInfo.launchMode : 0;
    ...
    final ActivityRecord r = new ActivityRecord.Builder(mService)
        ...
        .setActivityInfo(aInfo)
        ...
        .build();
    ...
    mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
        request.voiceInteractor, startFlags, checkedOptions,
        inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, transition,
        isIndependent);

    ...
}

,可以看到,执行该方法会创建一个ActivityRecord并设置其ActivityInfoainfoActivityInfo中包含了LaunchMode,之后方法调用了startActivityUnchecked方法:

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment,
        BalVerdict balVerdict,
        NeededUriGrants intentGrants, int realCallingUid, Transition transition,
        boolean isIndependentLaunch) {
        ...
        result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, options, inTask, inTaskFragment, balVerdict,
                intentGrants, realCallingUid);
        ...
}

,调用了startActivityInner方法:

计算启动标志launchingTaskFlags

int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment, BalVerdict balVerdict,
        NeededUriGrants intentGrants, int realCallingUid) {
    setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
            voiceSession, voiceInteractor, balVerdict.getCode(), realCallingUid);

    computeLaunchingTaskFlags();
    mIntent.setFlags(mLaunchFlags);

    ...

,在方法中,首先调用了setInitialState方法:

private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment, int startFlags,
        ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,
        IVoiceInteractor voiceInteractor, @BalCode int balCode, int realCallingUid) {
    reset(false);
    ...
    mLaunchMode = r.launchMode;

    mLaunchFlags = adjustLaunchFlagsToDocumentMode(
                r, LAUNCH_SINGLE_INSTANCE == mLaunchMode,
                LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags());
    
    ...

    if (mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK) {
        mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }
    ...
}

,在方法中设置了mLaunchModemLaunchFlags,如果mLaunchModeLAUNCH_SINGLE_INSTANCE_PER_TASK,则设置mLaunchFlagsFLAG_ACTIVITY_NEW_TASK,然后startActivityInner调用了computeLauchingTaskFlags方法:

private void computeLaunchingTaskFlags() {
    ...
    if (mInTask == null) {
        ...
        } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
        } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
        }
    }
    ...
}

分为下面情况:

  1. 如果源Activity的启动模式为LAUCH_SINGLE_INSTANCE,则需要为新Activity创建一个新任务,于是设置mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK
  2. 如果Activity的启动模式为LAUCH_SINGLE_INSTANCELAUNCH_SINGLE_TASK,对于第一种情况,由于inTask为空,于是设置mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK

继续到startActivtyInner中:

计算目标task


int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment, BalVerdict balVerdict,
        NeededUriGrants intentGrants, int realCallingUid) {
    
    ...

    final Task prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
    final Task prevTopTask = prevTopRootTask != null ? prevTopRootTask.getTopLeafTask() : null;

    final Task reusedTask = resolveReusableTask(includeLaunchedFromBubble);

    ...


    final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
    final boolean newTask = targetTask == null;
    mTargetTask = targetTask;

    ...

}

方法首先调用了resolveReusableTask方法:

private Task resolveReusableTask(boolean includeLaunchedFromBubble) {
    boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
        (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
        || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK);
    
    if (putIntoExistingTask) {
        if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
            intentActivity = mRootWindowContainer.findActivity(mIntent, mStartActivity.info,
                    false );
   
            ...
        } ...
        else {
            intentActivity =
                    mRootWindowContainer.findTask(mStartActivity, mPreferredTaskDisplayArea,
                            includeLaunchedFromBubble);
        }
    }
    ...
    return intentActivity != null ? intentActivity.getTask() : null;
        
}

,如果LaunchFlagsFLAG_ACTIVITY_NEW_TASK(LaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0,表示要在一个新进程中创建Activity同时不允许Activity在多个进程中存在实例,此时需要找到一个可以复用的task,同样,如果LaunchModeLAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK,如果有现有的包含他们的task,则就要在已存在的task中找到他们所在的task并加入,然后方法会找到Actiivty可以复用的task

通过computeTargetTask方法,得出启动Activity的task:

private Task computeTargetTask() {
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        return null;
    } else if (mSourceRecord != null) {
        return mSourceRecord.getTask();
    } else if (mInTask != null) {
        if (!mInTask.isAttached()) {
            getOrCreateRootTask(mStartActivity, mLaunchFlags, mInTask, mOptions);
        }
        return mInTask;
    } else {
        final Task rootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, null /* task */,
                mOptions);
        final ActivityRecord top = rootTask.getTopNonFinishingActivity();
        if (top != null) {
            return top.getTask();
        } else {
            rootTask.removeIfPossible("computeTargetTask");
        }
    }
    return null;
}
  1. 当一个Activity不需要添加到任何一个task时,返回null,表示需要新建一个task
  2. 否则,当源Activity存在时,将其添加到源Activity的task中
  3. 如果指定的task不为空,则将其添加到指定的task中
  4. 否则,获取根task,并获取根task的top Activity,若不为空,返回该根task

Activity的复用

startActivityInner中调用了如下方法:

private int deliverToCurrentTopIfNeeded(Task topRootTask, NeededUriGrants intentGrants) {
    ...
}

,判断是否复用当前的top Activity

startActivityInner中,还调用了如下方法:

if (targetTaskTop != null) {
    ...
    startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants, balVerdict);
}
int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask,
        NeededUriGrants intentGrants, BalVerdict balVerdict) {
    ...
    if (reusedTask != null) {
        if (targetTask.intent == null) {
            targetTask.setIntent(mStartActivity);
        } 
        ...
    }
    ...
    //将要复用的task放到最顶端
    //如果需要删除栈中对应记录则执行删除
    setTargetRootTaskIfNeeded(targetTaskTop);
    ...
    complyActivityFlags(targetTask,
            reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants);

    if (mAddingToTask) {
        mSupervisor.getBackgroundActivityLaunchController().clearTopIfNeeded(targetTask,
                mSourceRecord, mStartActivity, mCallingUid, mRealCallingUid, mLaunchFlags,
                mBalCode);
        return START_SUCCESS;
    }

    if (mMovedToTopActivity != null) {
        targetTaskTop = mMovedToTopActivity;
    }
    targetTaskTop = targetTaskTop.finishing
            ? targetTask.getTopNonFinishingActivity()
            : targetTaskTop;


    resumeTargetRootTaskIfNeeded();

    ...

    mLastStartActivityRecord = targetTaskTop;
    return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
}

观察不同Activity复用的情况:

  1. 对于standard模式:

  2. 对于singleTop模式:在deliverToCurrentTopIfNeeded中,存在:
    final ActivityRecord top = topRootTask.topRunningNonDelayedActivityLocked(mNotTop);
    final boolean dontStart = top != null
         && top.mActivityComponent.equals(mStartActivity.mActivityComponent)
         && top.mUserId == mStartActivity.mUserId
         && top.attachedToProcess()
         && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
         || LAUNCH_SINGLE_TOP == mLaunchMode)
         && (!top.isActivityTypeHome() || top.getDisplayArea() == mPreferredTaskDisplayArea);
    if (!dontStart) {
     return START_SUCCESS;
    }
    ...
    top.getTaskFragment().clearLastPausedActivity();
    if (mDoResume) {
     mRootWindowContainer.resumeFocusedTasksTopActivities();
    }
    ...
    deliverNewIntent(top, intentGrants);
    ...
    

    ,当top Activity满足复用条件时,会复用该Activity且向其发送一个Intent

  3. 对于singleTask模式:

complyActivityFlags中,执行了如下语句:

else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                || isDocumentLaunchesIntoExisting(mLaunchFlags)
                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK,
                        LAUNCH_SINGLE_INSTANCE_PER_TASK)) {
    final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
        mLaunchFlags, finishCount);
    if (clearTop != null && !clearTop.finishing) {
        if (finishCount[0] > 0) {
            mMovedToTopActivity = clearTop;
        }
        if (clearTop.isRootOfTask()) {
            clearTop.getTask().setIntent(mStartActivity);
        }
        deliverNewIntent(clearTop, intentGrants);
    }
}

,如果选择了复用任务,则对该task进行清空

  1. 对于singleInstance模式: 在startActivityInner中进行判断:
    if (LAUNCH_SINGLE_INSTANCE == mLaunchMode && mSourceRecord != null
         && targetTask == mSourceRecord.getTask()) {
     final ActivityRecord activity = mRootWindowContainer.findActivity(mIntent,
             mStartActivity.info, false);
     if (activity != null && activity.getTask() != targetTask) {
         activity.destroyIfPossible("Removes redundant singleInstance");
     }
    }
    

    ,如果目标Activity需要运行在源Activity的task中时,需要销毁其他task中的目标Activity,对于singleInstance模式,在computeTargetTask中,mSourceRecord是优先于mInTask

  2. 对于singleInstancePerTask模式:
else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                || isDocumentLaunchesIntoExisting(mLaunchFlags)
                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK,
                        LAUNCH_SINGLE_INSTANCE_PER_TASK)) {
    final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
        mLaunchFlags, finishCount);
    if (clearTop != null && !clearTop.finishing) {
        if (finishCount[0] > 0) {
            mMovedToTopActivity = clearTop;
        }
        if (clearTop.isRootOfTask()) {
            clearTop.getTask().setIntent(mStartActivity);
        }
        deliverNewIntent(clearTop, intentGrants);
    }
}

待更新…

LaunchFlags总结

LaunchFlag 含义
FLAG_ACTIVITY_CLEAR_TASK 会清空任务中的其他旧活动,需要与FLAG_ACTIVTTY_NEW_TASK一起使用
FLAG_ACTIVITY_CLEAR_TOP 在当前任务中时,在新活动上面的活动会被关闭,新活动不会重新启动,只会接收new intent
FLAG_ACTIIVTY_NEW_TASK 新活动会成为历史栈中的新任务的开始,如果新活动已存在于一个为它运行的任务中,那么不会启动,只会把该任务移到屏幕最前
FLAG_ACTIVITY_MULTIPLE_TASK FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_NEW_DOCUMENT一起使用,会在创建Activity时重新创建一个task
FLAG_ACTIVITY_NEW_DOCUMENT 给启动的活动开启一个新的任务记录