原创文章,转载注明出处。
任务栈管理是Activity中非常重要的一部分,这篇文章来学习下。代码继续使用的Android9.0源码.
一、关键类介绍
Activity任务栈主要牵涉到如下几个重要类:
ActivityRecord
: Activity对应的实体对象;
TaskRecord
:Activity任务栈,一个或多个ActivityRecord组成TaskRecord;
ActivityStack
:不是真正的Activity栈,他是TaskRecord管理类,一个或多个TaskRecord组成ActivityStack;
ActivityStackSupervisor
:ActivityStack的管理类。
在Android系统中,每个应用都有自己的Activity任务栈和内部对应的Activity,但是应用本身不会去管理他们,而且将Activity封装成ActivityRecord对象,丢给系统,交由系统来管理。
ActivityRecord
final class ActivityRecord {
ProcessRecord app //跑在哪个进程
TaskRecord task //跑在哪个task
ActivityInfo info // Activity信息
int mActivityType //Activity类型
ActivityState state //Activity状态
ApplicationInfo appInfo //跑在哪个app
ComponentName realActivity //组件名
String packageName //包名
String processName //进程名
int launchMode //启动模式
int userId // 该Activity运行在哪个用户id
…
}
以上信息,主要包含用户组,进程、Task、包信息、以及Activity自身状态和信息。
TaskRecord
final class TaskRecord {
ActivityStack stack; //当前所属的stack
final ArrayList mActivities;// 当前task的所有Activity列表
final int taskId
String affinity;// 是指root activity的affinity,即该Task中第一个Activity;
int mCallingUid;
String mCallingPackage; //调用者的包名
...
}
对ActivityRecord的管理主要是通过对mActivities集合的增删改查的操作来实现。
一个应用程序都有可能不止一个任务栈,那么对应真个系统来说,肯定是需要针对多个ActivityRecord进行统一的管理,那么这个类就叫ActivityStack,从名字上看很容易误以为它才是任务栈,其实不然。
final class ActivityStack {
ArrayList mTaskHistory //保存所有的Task列表
ArrayList mStacks; //所有stack列表
final int mStackId;
int mDisplayId;
final ArrayList mLRUActivities = new ArrayList<>(); //按LRU排列的Activity
final ArrayList mNoAnimActivities = new ArrayList<>();//没有转场动画的Activity
ActivityRecord mPausingActivity //正在pause的Activity
ActivityRecord mLastPausedActivity //最后pause的Activity
ActivityRecord mResumedActivity //已经resumed的Activity
ActivityRecord mLastStartedActivity//最后resumed的Activity
...
enum ActivityState { //Activity的各种生命周期状态
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}
...
}
从对象属性来看,首当其冲的还是TaskRecord集合,它是所有Task的集合, 具体方法也是针对mTaskHistory来进行增删改查操作。除此以外,它的内部还维护了mLRUActivities 和 mNoAnimActivities 这样的针对ActivityRecord的特殊集合,同时保存着对应Activity生命周期状态和对象。总体来看就是ActivityRecord 和 TaskRecord一把抓。
ActivityStackSupervisor是ActivityStack的管理类,但是实际上是由ActivityDisplay来统一管理的。
ActivityStackSupervisor在AMS构造方法中被初始化,对于没有分屏功能以及虚拟屏的情况下,ActivityStackSupervisor和ActivityDisplay是系统唯一的。
ActivityStackSupervisor
public final class ActivityStackSupervisor implements DisplayListener {
ActivityStack mHomeStack //桌面的stack(Launcher app Stack)
ActivityStack mFocusedStack //当前聚焦stack(App Stack)
…
}
mStacks集合保存所有ActivityStack。
ActivityDisplay
class ActivityDisplay extends ConfigurationContainer
implements WindowContainerListener {
…
private final ArrayList mStacks = new ArrayList<>();
…
private ActivityStack mHomeStack = null;
private ActivityStack mRecentsStack = null;
private ActivityStack mPinnedStack = null;
private ActivityStack mSplitScreenPrimaryStack = null;
…
}
以上对象之间的关系如下图所示:
二、从Activity启动流程来看任务栈管理
Activity启动过程中,start、pause、stop Activity都是先通过 应用 Binder IPC到 AMS,然后AMS 通知相关任务栈管理类进行任务栈调整,最后Binder IPC到应用,通过消息泵来分发对应生命周期的处理。那么这里我们看下startActivity中 AMS到ApplicationThread 中间任务栈工作部分来简单了解下整个任务栈的管理。代码基于android 9.0 。
先看一个整体流程图:
图用的是刘皇叔的,大流程上9.0依然是如此,只是代码处理细节有些许调整,直接借图了。
AMS先执行startActivity
5078 @Override
5079 public final int startActivity(IApplicationThread caller, String callingPackage,
5080 Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
5081 int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
5082 return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
5083 resultWho, requestCode, startFlags, profilerInfo, bOptions,
5084 UserHandle.getCallingUserId());
5085 }
这里没什么好讲的,直接调用startActivityAsUser。
startActivityAsUser有多个重载,最终执行:
5096 public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
5097 Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
5098 int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
5099 boolean validateIncomingUser) {
5100 enforceNotIsolatedCaller("startActivity");
5101
5102 userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
5103 Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
5104
5105 // TODO: Switch to user app stacks here.
5106 return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
5107 .setCaller(caller)
5108 .setCallingPackage(callingPackage)
5109 .setResolvedType(resolvedType)
5110 .setResultTo(resultTo)
5111 .setResultWho(resultWho)
5112 .setRequestCode(requestCode)
5113 .setStartFlags(startFlags)
5114 .setProfilerInfo(profilerInfo)
5115 .setActivityOptions(bOptions)
5116 .setMayWait(userId)
5117 .execute();
5118
5119 }
这里使用了建造者模式,通过ActivityStartController构造了ActivityStarter,Activity启动管理类.其中.setMayWait(userId)的方法内部会走mRequest.mayWait = true;
继续
ActivityStarter #execute
481 int execute() {
482 try {
483 // TODO(b/64750076): Look into passing request directly to these methods to allow
484 // for transactional diffs and preprocessing.
485 if (mRequest.mayWait) { //true
486 return startActivityMayWait(mRequest.caller, mRequest.callingUid,
487 mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
488 mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
489 mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
490 mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
491 mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
492 mRequest.inTask, mRequest.reason,
493 mRequest.allowPendingRemoteAnimationRegistryLookup);
494 } else {
495 return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
496 mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
497 mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
498 mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
499 mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
500 mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
501 mRequest.ignoreTargetSecurity, [mRequest.componentSpecified](http://mrequest.componentspecified/),
502 mRequest.outActivity, mRequest.inTask, mRequest.reason,
503 mRequest.allowPendingRemoteAnimationRegistryLookup);
504 }
505 } finally {
506 onExecutionComplete();
507 }
508 }
从前面mRequest.mayWait = true 可以知道这里会执行startActivityMayWait
ActivityStarter #startActivityMayWait
945 private int startActivityMayWait(IApplicationThread caller, int callingUid,
946 String callingPackage, Intent intent, String resolvedType,
947 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
948 IBinder resultTo, String resultWho, int requestCode, int startFlags,
949 ProfilerInfo profilerInfo, WaitResult outResult,
950 Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
951 int userId, TaskRecord inTask, String reason,
952 boolean allowPendingRemoteAnimationRegistryLookup) {
…
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
...
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
…
1099 int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
1100 voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
1101 callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
1102 ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
1103 allowPendingRemoteAnimationRegistryLookup);
...
1174 }
这个过程,收集了若干启动参数信息,包括intent、ActivityInfo、CallingPid、CallingUid、package信息以及startFlag等信息,之后传参给startActivity做处理, 如果mRequest.mayWait 为false,那么就省了startActivityMayWait,直接执行startActivity。至于false的场景暂时先不讨论,有兴趣可以自己追一下代码.
ActivityStarter #startActivity
528 private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
529 String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
530 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
531 IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
532 String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
533 SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
534 ActivityRecord[] outActivity, TaskRecord inTask, String reason,
535 boolean allowPendingRemoteAnimationRegistryLookup) {
536
537 if (TextUtils.isEmpty(reason)) {
538 throw new IllegalArgumentException("Need to specify a reason.");
539 }
540 mLastStartReason = reason; //获取启动原因
541 mLastStartActivityTimeMs = System.currentTimeMillis(); //获取启动时间
542 mLastStartActivityRecord[0] = null;
543 //这里又调用了一个startActivity
544 mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
545 aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
546 callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
547 options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
548 inTask, allowPendingRemoteAnimationRegistryLookup);
549
550 if (outActivity != null) {
551 // mLastStartActivityRecord[0] is set in the call to startActivity above.
552 outActivity[0] = mLastStartActivityRecord[0];
553 }
554
555 return getExternalResult(mLastStartActivityResult);
556 }
这个方法内部做的事情不多,简单地获取了取启动原因和时间,然后又调用了一个重载方法。
接着看:
571 private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
572 String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
573 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
574 IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
575 String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
576 SafeActivityOptions options,
577 boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
578 TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
579 int err = ActivityManager.START_SUCCESS;
580 // Pull the optional Ephemeral Installer-only bundle out of the options early.
581 final Bundle verificationBundle
582 = options != null ? options.popAppVerificationBundle() : null;
583 获取调用者进程记录对象
584 ProcessRecord callerApp = null;
585 if (caller != null) {
586 callerApp = mService.getRecordForAppLocked(caller);
587 if (callerApp != null) {
588 callingPid = callerApp.pid;
589 callingUid = callerApp.info.uid;
590 } else {
591 Slog.w(TAG, "Unable to find app for caller " + caller
592 + " (pid=" + callingPid + ") when starting: "
593 + intent.toString());
594 err = ActivityManager.START_PERMISSION_DENIED;
595 }
596 }
...
606 ActivityRecord sourceRecord = null;
607 ActivityRecord resultRecord = null;
608 if (resultTo != null) {
//获取调用者所在的Activity
609 sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
610 if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
611 "Will send result to " + resultTo + " " + sourceRecord);
612 if (sourceRecord != null) {
613 if (requestCode >= 0 && !sourceRecord.finishing) {
614 resultRecord = sourceRecord;
615 }
616 }
617 }
618
...//一系列问题的检查 。包括Activity、Intent、Class、Permission等,同时对多种error的情况做了判断
706 final ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();
...
//创建Activity的实体类
826 ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
827 callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
828 resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
829 mSupervisor, checkedOptions, sourceRecord);
830 if (outActivity != null) {
831 outActivity[0] = r;
832 }
…
//当前stack 成为focusedStack
840 final ActivityStack stack = mSupervisor.mFocusedStack;
841
842 // If we are starting an activity that is not from the same uid as the currently resumed
843 // one, check whether app switches are allowed.
844 if (voiceSession == null && (stack.getResumedActivity() == null
845 || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
// 前台stack还没有resume状态的Activity时, 则检查app切换是否允许
846 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
847 realCallingPid, realCallingUid, "Activity start")) {
// 当不允许切换,则把要启动的Activity添加到mPendingActivityLaunches对象, 并且直接返回.
848 mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
849 sourceRecord, startFlags, stack, callerApp));
850 ActivityOptions.abort(checkedOptions);
851 return ActivityManager.START_SWITCHES_CANCELED;
852 }
853 }
...
866 mController.doPendingActivityLaunches(false);
867
868 return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
869 true /* doResume */, checkedOptions, inTask, outActivity);
870 }
这个过程代码不少,整体来说,前面收集了一大把信息,在这里就派上用场了,简单说就是确认了调用进程、也通过PMS确认了要调用的Activity,并对一些列信息包括Activity、Intent、Class、Permission进行检查以及多重if else的error判断。如果满足条件,则封装成ActivityRecord。继续执行startActivity(又是startActivity...)。
1193 private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
1194 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
1195 int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
1196 ActivityRecord[] outActivity) {
1197 int result = START_CANCELED;
1198 try {
1199 mService.mWindowManager.deferSurfaceLayout();
1200 result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
1201 startFlags, doResume, options, inTask, outActivity);
1202 } finally {
1203 // If we are not able to proceed, disassociate the activity from the task. Leaving an
1204 // activity in an incomplete state can lead to issues, such as performing operations
1205 // without a window container.
1206 final ActivityStack stack = mStartActivity.getStack();
1207 if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {
1208 stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
1209 null /* intentResultData */, "startActivity", true /* oomAdj */);
1210 }
1211 mService.mWindowManager.continueSurfaceLayout();
1212 }
1213
1214 postStartActivityProcessing(r, result, mTargetStack);
1215
1216 return result;
1217 }
这里没太多内容,主要是执行了 startActivityUnchecked,我们先看这个方法
ActivityStarter # startActivityUnchecked
1220 private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
1221 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
1222 int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
1223 ActivityRecord[] outActivity) {
1225 setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
1226 voiceInteractor); //把方法参数赋值给ActivityStarter成员变量。
1227 //通过方法参数先明确一下:ActivityRecord r 为本次要启动的Activity,ActivityRecord sourceRecord为调用者Activity
1228 computeLaunchingTaskFlags(); //对启动模式进行检查与LaunchFlags赋值
1229
1230 computeSourceStack();
1231
1232 mIntent.setFlags(mLaunchFlags); //把计算好的LaunchFlags 给Intent
mReusedActivity = getReusableIntentActivity();//本次要调用的Activity在已存在的Task中则返回mReusedActivity
...//根据LaunchFlags 与启动模式 来调整被调用Activity所在的任务栈
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) { //singleTop or SingleInstance的处理
// 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);
}
}
...
1408 if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
1409 && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { //根启动Activity是使用 FLAG_ACTIVITY_NEW_TASK
1410 newTask = true;
//创建新的TaskRecord
1411 result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
1412 }
...
1466 mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
1467 mOptions);
1468 }
...
1477 return START_SUCCESS;
1478 }
startActivityUnchecked方法主要是根据LaunchFlags 与启动模式 来调整被调用Activity所在的任务栈
根Activity对应的flag是FLAG_ACTIVITY_NEW_TASK,则创建新的TaskRecord ,并执行mSupervisor.resumeFocusedStackTopActivityLocked。
ActivityStackSupervisor#resumeFocusedStackTopActivityLocked
2214 boolean resumeFocusedStackTopActivityLocked(
2215 ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
2216
2217 if (!readyToResume()) {
2218 return false;
2219 }
2220
2221 if (targetStack != null && isFocusedStack(targetStack)) {
2222 return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
2223 }
2224
2225 final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
2226 if (r == null || !r.isState(RESUMED)) {
2227 mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
2228 } else if (r.isState(RESUMED)) {
2229 // Kick off any lingering app transitions form the MoveTaskToFront operation.
2230 mFocusedStack.executeAppTransition(targetOptions);
2231 }
2232
2233 return false;
2234 }
//当前Activity所在stack是focusedStack,或者当前focusedStack的栈顶活动的activity为空或者不是resume状态
那么执行resumeTopActivityUncheckedLocked
ActivityStack#resumeTopActivityUncheckedLocked
2282 boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
2283 if (mStackSupervisor.inResumeTopActivity) {
2284 // Don't even start recursing.
2285 return false;
2286 }
2287
2288 boolean result = false;
2289 try {
2290 // Protect against recursion.
2291 mStackSupervisor.inResumeTopActivity = true;
2292 result = resumeTopActivityInnerLocked(prev, options);
2301 final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
2302 if (next == null || !next.canTurnScreenOn()) {
2303 checkReadyForSleep();
2304 }
2305 } finally {
2306 mStackSupervisor.inResumeTopActivity = false;
2307 }
2308
2309 return result;
2310 }
再看ActivityStack#resumeTopActivityInnerLocked
2330 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
…
//当前存在其他的Activity处于Resume状态,那么会走 startPausingLocked。
2442 if (mResumedActivity != null) {
//主要是通知ActivityThread执行schedulePause流程
2445 pausing |= startPausingLocked(userLeaving, false, next, false);
2446 }
…
//最终都会调用到这
2754 mStackSupervisor.startSpecificActivityLocked(next, true, true);
2755
2758 return true;
2759 }
1678 void startSpecificActivityLocked(ActivityRecord r,
1679 boolean andResume, boolean checkConfig) {
1680 //获取对应进程
1681 ProcessRecord app = mService.getProcessRecordLocked(r.processName,
1682 r.info.applicationInfo.uid, true);
1683
1684 getLaunchTimeTracker().setLaunchTime(r);
1685
1686 if (app != null && app.thread != null) {
1687 try {
1688 if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
1689 || !"android".equals(r.info.packageName)) {
1694 app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
1695 mService.mProcessStats);
1696 }
//如果进程存在,则执行scheduleLauncherActivity流程
1697 realStartActivityLocked(r, app, andResume, checkConfig);
1698 return;
1699 } catch (RemoteException e) {
1700 Slog.w(TAG, "Exception when starting activity "
1701 + r.intent.getComponent().flattenToShortString(), e);
1702 }
1703
1704 // If a dead object exception was thrown -- fall through to
1705 // restart the application.
1706 }
1707 //如果进程不存在,则执行进程创建流程
1708 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1709 "activity", r.intent.getComponent(), false, false, true);
1710 }
简单总结:
- startActivity首先会收集启动数据,经过验证如果满足条件,则会创建一个ActivityRecord。
- 根据flag 与启动模式 调整任务栈。
- 之前如果已经存在其他的Resume状态的Activity,那么需要先让它pause。
- 最后看所在进程是否存在,如果不存在则还需要走进程启动流程。
三、启动模式
- standard(默认) :启动一个新Activity就加入栈顶,不考虑重复。
- singleTop :栈顶复用。
- singleTask :栈内复用,且之上的所有Activity统统出栈。
- singleInstance :独享栈。
四、任务栈两种主要设置操作
同一个程序不同activity放入不同的栈中:为不同的activity设置不同的taskaffnity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。
不同程序的activity放入同一个栈中:activity 标签中加入: android:allowTaskReparenting=“true” 和 android:taskAffinity=“same label”。
一个小demo演示下, 代码很简单就两个Activity,点击click跳转:
不做任何设置,同一app中不同activity在相同task中。
Running activities (most recent first):
TaskRecord{707a762 #1205 A=com.stan.appmodule U=0 StackId=1 sz=2}
Run #1: ActivityRecord{6864c55 u0 com.stan.appmodule/.BActivity t1205}
Run #0: ActivityRecord{eb6d3fa u0 com.stan.appmodule/.MainActivity t1205}
为不同的activity设置不同的taskaffnity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。
Running activities (most recent first):
TaskRecord{1a2b940 #1209 A=com.stan.appmodule.BActivity U=0 StackId=1 sz=1}
Run #1: ActivityRecord{d80b33c u0 com.stan.appmodule/.BActivity t1209}
TaskRecord{e3a9079 #1208 A=com.stan.appmodule.MainActivity U=0 StackId=1 sz=1}
Run #0: ActivityRecord{d369326 u0 com.stan.appmodule/.MainActivity t1208}
不同程序的activity放入同一个栈中:activity 标签中加入: android:allowTaskReparenting=“true” 和 android:taskAffinity=“same label”。
两个app: com.stan.appmodule 和 com.stan.appmodule2 ,对两者的MainActivity设置如上属性
Running activities (most recent first):
TaskRecord{5a7f1be #1210 A=com.stan.appmodule.MainActivity U=0 StackId=1 sz=2}
Run #1: ActivityRecord{9c70786 u0 com.stan.appmodule2/.MainActivity t1210}
Run #0: ActivityRecord{e989b91 u0 com.stan.appmodule/.MainActivity t1210}