Activity的launchMode详细分析

在研究了Activity的启动过程后,我觉得很有必要对Activity的launchMode进行分析一下,因为到目前为止,我发现网上对launchMode的讲解都是通过实例讲解,看完了总是似懂非懂的感觉,并没有根本上理解launchMode的原理。这里我会从源码的角度讲解launchMode。相信大家会和我一样,看了源码之后就会有一种豁然开朗的感觉。

 

Activity的启动模式一种有四种,分别如下:

1、standard

2、singleTop

3、singleTask

4、singleInstance

 

这里我们分两种情况讨论上述四种启动模式:app内和app之间

首先讨论app内

standard:不论当前任务栈中是否存在该Activity,都会新建一个Activity,如 任务栈为A B,要启动B 那么任务栈为 A B B

singleTop:如果当前要创建的Activity就在任务栈的顶端,那么不会创建新的Activity,仅仅调用Activity的onNewIntent,如果不在栈顶(或者栈中没有该Activity),那么还是会创建新的Activity,如任务栈为A B 启动B  任务栈变为 A B 如果 启动A 那么任务栈为 A B A

singleTask:如果当前任务中存在要启动的Activity,那么就不会创建新的Activity,如果不存在就会创建新的Activity,如任务栈为 A B C,启动B ,那么任务栈就会变为A B

singleInstance:将一个Activity的launchMode设置为该值时,表明这个Activity独自占用一个任务队列,这个队列中不让在加入其他的Activity

不同的app之间:

既然在不同的app之间,那么就说明是两个任务栈,并且有一个处理前台,一个运行在后台

standard:当前台的Activity启动后台任务的Activity,不管这个Activity在后台任务栈中是否已经存在,都会创建一个新的Activity,并将它加入前台的任务栈中

singleTop:如果前台的Activity启动后台任务的Activity,并且这个Activity已经在后台任务的栈顶,和app内不同的是,这里还不能确定是否会创建新的Activity,这里还需要看启动Activity的Intent里面是否有Intent.FLAG_ACTIVITY_NEW_TASK,如果此标记,那么就会将后台的任务队列移动到前端,如 前端任务栈 A B 后端任务栈 E F C,现在前端需要启动一个C,如果有Intent.FLAG_ACTIVITY_NEW_TASK,那么后端任务栈就会移到前端(并调用C的onNewIntent),前端栈退居后端。如果没有这个标记,那么仅仅就是在前端任务栈中创建一个新的Activity C。

singleTask:如果前台的Activity启动后台任务的Activity,不管这个Activity是否在栈顶,都会将后台的任务栈移到前台,前台任务栈移至后台。这里不需要考虑标记问题,因为被启动的Activity如果是singleTask,那么自动在启动Activity的intent中加入上述标记。

singleInstance:如果前台Activity启动后台任务的Activity,如果后台任务栈中已经有该Activity,那么就会调用该Activity的onNewIntent,并且后台任务还是在后台。如果后台任务栈中没有该Activity,那么会重新创建一个Acitivyt,并单独放入一个任务栈,其实在启动该Acitivity的Intent中也会加入上述标记

 

其实还有一种情况比较特殊,不过很少使用,就是在一个app之间,我们给某一个Activity配置了taskAffinity属性,这个属性会影响singleTask等属性,这个可以大家自己去分析。

下面我们就来看看和launchMode处理有关的代码吧

对launchMode处理的逻辑主要是放在了ActivityStack的startActivityUncheckedLocked方法中,这份方法的逻辑有些复杂,我们来一部分一部分的分析:

第一部分:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. if (sourceRecord == null) {  
  2.            // This activity is not being started from another...  in this  
  3.            // case we -always- start a new task.  
  4.            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {  
  5.                Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "  
  6.                      + intent);  
  7.                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;  
  8.            }  
  9.        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
  10.            // The original activity who is starting us is running as a single  
  11.            // instance...  this new activity it is starting must go on its  
  12.            // own task.  
  13.            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;  
  14.        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE  
  15.                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {  
  16.            // The activity being started is a single instance...  it always  
  17.            // gets launched into its own task.  
  18.            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;  
  19.        }  



 

首先判断sourceRecord是否为Null(桌面启动一个Activity或者通过Context启动一个Activity时sourceRecord为null),如果在启动的Intent中没有FLAG_ACTIVITY_NEW_TASK那么就会在该Intent中添加该标记。

如果sourceRecord的launchMode设置的是singleinstance,那么就会在Intent添加FLAG_ACTIVITY_NEW_TASK,因为对于singleinstance的Activity,是不会和别人共享一个队列的。

如果被启动的Activity的launchMode是singleinstance或者singletask,那么也会在Intent中添加FLAG_ACTIVITY_NEW_TASK标记(上面我们已经说过)。

 

 

在看第二部分代码

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
  2.     // For whatever reason this activity is being launched into a new  
  3.     // task...  yet the caller has requested a result back.  Well, that  
  4.     // is pretty messed up, so instead immediately send back a cancel  
  5.     // and let the new task continue launched as normal without a  
  6.     // dependency on its originator.  
  7.     Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");  
  8.     sendActivityResultLocked(-1,  
  9.             r.resultTo, r.resultWho, r.requestCode,  
  10.         Activity.RESULT_CANCELED, null);  
  11.     r.resultTo = null;  
  12. }  



 

通过这段代码可以当Intent中包含了Intent.FLAG_ACTIVITY_NEW_TASK标记时,是不能使用startActivityforResult方法启动Activity的,也就是说如果一个Activity是sinleTask或者singleInstance时,都不能通过startActivityForResult方法调起(可以调起,但是无法传回值)

第三部分代码

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. boolean addingToTask = false;  
  2.         boolean movedHome = false;  
  3.         TaskRecord reuseTask = null;  
  4.         if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&  
  5.                 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)  
  6.                 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK  
  7.                 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
  8.             // If bring to front is requested, and no result is requested, and  
  9.             // we can find a task that was started with this same  
  10.             // component, then instead of launching bring that one to the front.  
  11.             if (r.resultTo == null) {  
  12.                 // See if there is a task to bring to the front.  If this is  
  13.                 // a SINGLE_INSTANCE activity, there can be one and only one  
  14.                 // instance of it in the history, and it is always in its own  
  15.                 // unique task, so we do a special search.  
  16.                 ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE  
  17.                         ? findTaskLocked(intent, r.info)  
  18.                         : findActivityLocked(intent, r.info);  
  19.                 if (taskTop != null) {  
  20.                     if (taskTop.task.intent == null) {  
  21.                         // This task was started because of movement of  
  22.                         // the activity based on affinity...  now that we  
  23.                         // are actually launching it, we can assign the  
  24.                         // base intent.  
  25.                         taskTop.task.setIntent(intent, r.info);  
  26.                     }  
  27.                     // If the target task is not in the front, then we need  
  28.                     // to bring it to the front...  except...  well, with  
  29.                     // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like  
  30.                     // to have the same behavior as if a new instance was  
  31.                     // being started, which means not bringing it to the front  
  32.                     // if the caller is not itself in the front.  
  33.                     ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);  
  34.                     if (curTop != null && curTop.task != taskTop.task) {  
  35.                         r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);  
  36.                         boolean callerAtFront = sourceRecord == null  
  37.                                 || curTop.task == sourceRecord.task;  
  38.                         if (callerAtFront) {  
  39.                             // We really do want to push this one into the  
  40.                             // user's face, right now.  
  41.                             movedHome = true;  
  42.                             moveHomeToFrontFromLaunchLocked(launchFlags);  
  43.                             moveTaskToFrontLocked(taskTop.task, r, options);  
  44.                             options = null;  
  45.                         }  
  46.                     }  
  47.                     // If the caller has requested that the target task be  
  48.                     // reset, then do so.  
  49.                     if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {  
  50.                         taskTop = resetTaskIfNeededLocked(taskTop, r);  
  51.                     }  
  52.                     if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)  != 0) {  
  53.                         // We don't need to start a new activity, and  
  54.                         // the client said not to do anything if that  
  55.                         // is the case, so this is it!  And for paranoia, make  
  56.                         // sure we have correctly resumed the top activity.  
  57.                         if (doResume) {  
  58.                             resumeTopActivityLocked(null, options);  
  59.                         } else {  
  60.                             ActivityOptions.abort(options);  
  61.                         }  
  62.                         return ActivityManager.START_RETURN_INTENT_TO_CALLER;  
  63.                     }  
  64.                     if ((launchFlags &  
  65.                             (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))  
  66.                             == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {  
  67.                         // The caller has requested to completely replace any  
  68.                         // existing task with its new activity.  Well that should  
  69.                         // not be too hard...  
  70.                         reuseTask = taskTop.task;  
  71.                         performClearTaskLocked(taskTop.task.taskId);  
  72.                         reuseTask.setIntent(r.intent, r.info);  
  73.                     } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0  
  74.                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK  
  75.                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
  76.                         // In this situation we want to remove all activities  
  77.                         // from the task up to the one being started.  In most  
  78.                         // cases this means we are resetting the task to its  
  79.                         // initial state.  
  80.                         ActivityRecord top = performClearTaskLocked(  
  81.                                 taskTop.task.taskId, r, launchFlags);  
  82.                         if (top != null) {  
  83.                             if (top.frontOfTask) {  
  84.                                 // Activity aliases may mean we use different  
  85.                                 // intents for the top activity, so make sure  
  86.                                 // the task now has the identity of the new  
  87.                                 // intent.  
  88.                                 top.task.setIntent(r.intent, r.info);  
  89.                             }  
  90.                             logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);  
  91.                             top.deliverNewIntentLocked(callingUid, r.intent);  
  92.                         } else {  
  93.                             // A special case: we need to  
  94.                             // start the activity because it is not currently  
  95.                             // running, and the caller has asked to clear the  
  96.                             // current task to have this activity at the top.  
  97.                             addingToTask = true;  
  98.                             // Now pretend like this activity is being started  
  99.                             // by the top of its task, so it is put in the  
  100.                             // right place.  
  101.                             sourceRecord = taskTop;  
  102.                         }  
  103.                     } else if (r.realActivity.equals(taskTop.task.realActivity)) {  
  104.                         // In this case the top activity on the task is the  
  105.                         // same as the one being launched, so we take that  
  106.                         // as a request to bring the task to the foreground.  
  107.                         // If the top activity in the task is the root  
  108.                         // activity, deliver this new intent to it if it  
  109.                         // desires.  
  110.                         if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0  
  111.                                 && taskTop.realActivity.equals(r.realActivity)) {  
  112.                             logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);  
  113.                             if (taskTop.frontOfTask) {  
  114.                                 taskTop.task.setIntent(r.intent, r.info);  
  115.                             }  
  116.                             taskTop.deliverNewIntentLocked(callingUid, r.intent);  
  117.                         } else if (!r.intent.filterEquals(taskTop.task.intent)) {  
  118.                             // In this case we are launching the root activity  
  119.                             // of the task, but with a different intent.  We  
  120.                             // should start a new instance on top.  
  121.                             addingToTask = true;  
  122.                             sourceRecord = taskTop;  
  123.                         }  
  124.                     } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {  
  125.                         // In this case an activity is being launched in to an  
  126.                         // existing task, without resetting that task.  This  
  127.                         // is typically the situation of launching an activity  
  128.                         // from a notification or shortcut.  We want to place  
  129.                         // the new activity on top of the current task.  
  130.                         addingToTask = true;  
  131.                         sourceRecord = taskTop;  
  132.                     } else if (!taskTop.task.rootWasReset) {  
  133.                         // In this case we are launching in to an existing task  
  134.                         // that has not yet been started from its front door.  
  135.                         // The current task has been brought to the front.  
  136.                         // Ideally, we'd probably like to place this new task  
  137.                         // at the bottom of its stack, but that's a little hard  
  138.                         // to do with the current organization of the code so  
  139.                         // for now we'll just drop it.  
  140.                         taskTop.task.setIntent(r.intent, r.info);  
  141.                     }  
  142.                     if (!addingToTask && reuseTask == null) {  
  143.                         // We didn't do anything...  but it was needed (a.k.a., client  
  144.                         // don't use that intent!)  And for paranoia, make  
  145.                         // sure we have correctly resumed the top activity.  
  146.                         if (doResume) {  
  147.                             resumeTopActivityLocked(null, options);  
  148.                         } else {  
  149.                             ActivityOptions.abort(options);  
  150.                         }  
  151.                         return ActivityManager.START_TASK_TO_FRONT;  
  152.                     }  
  153.                 }  
  154.             }  
  155.         }  

 

这段代码的逻辑有些复杂,但是功能很简单,就是为要启动的Activity寻找或者创建一个任务栈,现在我使用singleTask为例,跟踪一下上述代码流程。

假设后台任务栈为 A B C,前台任务中要启动一个Activity B,我们就使用这个需求来跟踪上面的代码逻辑。

首先注意默认的addingToTask是false,reuseTask为null,由于是singleTask的,所以((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)是成立的,即使这里不成立,后面的逻辑也是成立,所以必然进入该if语句

继续跟进代码,会发现调用了findTaskLocked方法返回一个ActivityRecord,你可以查看findTaskLocked的逻辑,你会知道这个ActiivtyRecord 就是对应的是Activity C,继续往下走,就会调用 moveTaskToFrontLocked将后台任务移动到前台,由于我们考虑的是launchMode是singleTask,所以将会进入

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0  
  2.                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK  
  3.                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE)  


进入上面的if语句之后,就会调用performClearTaskLocked返回一个ActivityRecord,你可以去研究一下performClearTaskLocked的逻辑,这个方法传入了一个ActivityRecord r,就是将任务栈中r之上的AcrivityRecord 清除掉,并返回ActivityRecord r,这里返回的ActivityRecord 对应的就是Activity B。接着调用Activity B的onNewIntent方法。执行了这个else if,其他else if是都不会执行的,所以就直接执行到了

 

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. if (!addingToTask && reuseTask == null) {  
  2.                    // We didn't do anything...  but it was needed (a.k.a., client  
  3.                    // don't use that intent!)  And for paranoia, make  
  4.                    // sure we have correctly resumed the top activity.  
  5.                    if (doResume) {  
  6.                        resumeTopActivityLocked(null, options);  
  7.                    } else {  
  8.                        ActivityOptions.abort(options);  
  9.                    }  
  10.                    return ActivityManager.START_TASK_TO_FRONT;  
  11.                }  


这里直接调用了resumeTopActivityLocked方法。到这里singleTask就分析完了,其他的启动模式大家可以按照这种思路进行分析。

 

 

第四部分代码:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. if (r.packageName != null) {  
  2.             // If the activity being launched is the same as the one currently  
  3.             // at the top, then we need to check if it should only be launched  
  4.             // once.  
  5.             ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);  
  6.             if (top != null && r.resultTo == null) {  
  7.                 if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {  
  8.                     if (top.app != null && top.app.thread != null) {  
  9.                         if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0  
  10.                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP  
  11.                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {  
  12.                             logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);  
  13.                             // For paranoia, make sure we have correctly  
  14.                             // resumed the top activity.  
  15.                             if (doResume) {  
  16.                                 resumeTopActivityLocked(null);  
  17.                             }  
  18.                             ActivityOptions.abort(options);  
  19.                             if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {  
  20.                                 // We don't need to start a new activity, and  
  21.                                 // the client said not to do anything if that  
  22.                                 // is the case, so this is it!  
  23.                                 return ActivityManager.START_RETURN_INTENT_TO_CALLER;  
  24.                             }  
  25.                             top.deliverNewIntentLocked(callingUid, r.intent);  
  26.                             return ActivityManager.START_DELIVERED_TO_TOP;  
  27.                         }  
  28.                     }  
  29.                 }  
  30.             }  
  31.   
  32.         } else {  
  33.             if (r.resultTo != null) {  
  34.                 sendActivityResultLocked(-1,  
  35.                         r.resultTo, r.resultWho, r.requestCode,  
  36.                     Activity.RESULT_CANCELED, null);  
  37.             }  
  38.             ActivityOptions.abort(options);  
  39.             return ActivityManager.START_CLASS_NOT_FOUND;  
  40.         }  
  41.   
  42.         boolean newTask = false;  
  43.         boolean keepCurTransition = false;  
  44.   
  45.         // Should this be considered a new task?  
  46.         if (r.resultTo == null && !addingToTask  
  47.                 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
  48.             if (reuseTask == null) {  
  49.                 // todo: should do better management of integers.  
  50.                 mService.mCurTask++;  
  51.                 if (mService.mCurTask <= 0) {  
  52.                     mService.mCurTask = 1;  
  53.                 }  
  54.                 r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);  
  55.                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r  
  56.                         + " in new task " + r.task);  
  57.             } else {  
  58.                 r.setTask(reuseTask, reuseTask, true);  
  59.             }  
  60.             newTask = true;  
  61.             if (!movedHome) {  
  62.                 moveHomeToFrontFromLaunchLocked(launchFlags);  
  63.             }  
  64.               
  65.         } else if (sourceRecord != null) {  
  66.             if (!addingToTask &&  
  67.                     (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {  
  68.                 // In this case, we are adding the activity to an existing  
  69.                 // task, but the caller has asked to clear that task if the  
  70.                 // activity is already running.  
  71.                 ActivityRecord top = performClearTaskLocked(  
  72.                         sourceRecord.task.taskId, r, launchFlags);  
  73.                 keepCurTransition = true;  
  74.                 if (top != null) {  
  75.                     logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);  
  76.                     top.deliverNewIntentLocked(callingUid, r.intent);  
  77.                     // For paranoia, make sure we have correctly  
  78.                     // resumed the top activity.  
  79.                     if (doResume) {  
  80.                         resumeTopActivityLocked(null);  
  81.                     }  
  82.                     ActivityOptions.abort(options);  
  83.                     return ActivityManager.START_DELIVERED_TO_TOP;  
  84.                 }  
  85.             } else if (!addingToTask &&  
  86.                     (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {  
  87.                 // In this case, we are launching an activity in our own task  
  88.                 // that may already be running somewhere in the history, and  
  89.                 // we want to shuffle it to the front of the stack if so.  
  90.                 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);  
  91.                 if (where >= 0) {  
  92.                     ActivityRecord top = moveActivityToFrontLocked(where);  
  93.                     logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);  
  94.                     top.updateOptionsLocked(options);  
  95.                     top.deliverNewIntentLocked(callingUid, r.intent);  
  96.                     if (doResume) {  
  97.                         resumeTopActivityLocked(null);  
  98.                     }  
  99.                     return ActivityManager.START_DELIVERED_TO_TOP;  
  100.                 }  
  101.             }  
  102.             // An existing activity is starting this new activity, so we want  
  103.             // to keep the new one in the same task as the one that is starting  
  104.             // it.  
  105.             r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);  
  106.             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r  
  107.                     + " in existing task " + r.task);  
  108.   
  109.         } else {  
  110.             // This not being started from an existing activity, and not part  
  111.             // of a new task...  just put it in the top task, though these days  
  112.             // this case should never happen.  
  113.             final int N = mHistory.size();  
  114.             ActivityRecord prev =  
  115.                 N > 0 ? mHistory.get(N-1) : null;  
  116.             r.setTask(prev != null  
  117.                     ? prev.task  
  118.                     : new TaskRecord(mService.mCurTask, r.info, intent), null, true);  
  119.             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r  
  120.                     + " in new guessed " + r.task);  
  121.         }  
  122.   
  123.         mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,  
  124.                 intent, r.getUriPermissionsLocked());  
  125.   
  126.         if (newTask) {  
  127.             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);  
  128.         }  
  129.         logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);  
  130.         startActivityLocked(r, newTask, doResume, keepCurTransition, options);  
  131.         return ActivityManager.START_SUCCESS;  



 

我刚刚使用singleTask模式分析时,并没有走到这里,大家可以另一种情况来分析,就可以走到这里。

后台任务栈 A B,前台任务栈  E F,在前台任务栈中要启动后台任务的一个Activity C,也就是说后台任务栈中不存在C的情况,或者在一个app内通过配置taskAffinity属性也可以走到这里。

posted @ 2017-03-12 12:06  天涯海角路  阅读(266)  评论(0)    收藏  举报