深入理解Activity啟動流程(四)–Activity Task的調(diào)度算法

本系列博客將詳細闡述Activity的啟動流程。
深入理解Activity啟動流程(一)–Activity啟動的概要流程
深入理解Activity啟動流程(二)–Activity啟動相關類的類圖
深入理解Activity啟動流程(三)–Activity啟動的詳細流程1
深入理解Activity啟動流程(三)–Activity啟動的詳細流程2

前面兩篇博客介紹了Activity的詳細啟動流程,提到ActivityStack類的startActivityUncheckedLocked方法負責調(diào)度ActivityRecord和Task,并且調(diào)度算法非常復雜,需結合實際場景分析調(diào)度算法。本篇博客將介紹startActivityUncheckedLocked方法的具體實現(xiàn),本結合實際場景分析調(diào)度算法。
startActivityUncheckedLocked方法的具體實現(xiàn)

final int startActivityUncheckedLocked(ActivityRecord r,
        ActivityRecord sourceRecord, int startFlags, boolean doResume,
        Bundle options) {
    //... 
    //如果從Launcher程序啟動應用,launchFlags為
    //FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 
    //否則一般情況下launcheFlags為0,除非啟動Activity時設置了特殊的flag
    int launchFlags = intent.getFlags();      
    //啟動Activity時默認不會設置FLAG_ACTIVITY_PREVIOUS_IS_TOP 
    //故此notTop默認情況下會是null
    ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
            != 0 ? r : null; 
    //默認情況下startFlags不會設置START_FLAG_ONLY_IF_NEEDED
    // If the onlyIfNeeded flag is set, then we can do this if the activity
    // being launched is the same as the one making the call...  or, as
    // a special case, if we do not know the caller then we count the
    // current top activity as the caller.
    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
         //...默認情況下這里的代碼不會執(zhí)行
    }    
    //根據(jù)被啟動的Activity和sourceRecord設置標志
    //launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK
    //如果從通知欄啟動應用 sourceRecord == null
    if (sourceRecord == null) {
        // This activity is not being started from another...  in this
        // case we -always- start a new task.
        if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            Slog.w(TAG, "startActivity called from non-Activity context;" 
                  +"forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
                  + intent);
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        // The original activity who is starting us is running as a single
        // instance...  this new activity it is starting must go on its
        // own task.
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
        // The activity being started is a single instance...  it always
        // gets launched into its own task.
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }
  //一般情況下r.resultTo 不為null,它是啟動該Activity的Activity,
  //如果從通知欄啟動Activity 則r.result為null
  if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
      //...
      r.resultTo = null;
  }       
    //addingToTask 如果為true表示正在添加至某個task,
    //  后續(xù)需要將r添加至sourceRecord所在的task
    boolean addingToTask = false;
    //movedHome表示是否移動home task
    boolean movedHome = false;
    //reuseTask 如果不為null,則表示已存在task,會重用這個task,
    //                      但是這個Task里的所有Activity會被清除掉,
    //                      需要將r加入這個task  
    TaskRecord reuseTask = null;       
    if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //從通知欄啟動時r.resultTo == null
        //如果launchFlags設置了FLAG_ACTIVITY_NEW_TASK,r.resultTo也會為null
        if (r.resultTo == null) {
            //查找ActivityRecord棧,看要啟動的activity是否已有相關task,
            //如果已經(jīng)有相關task,則不需要創(chuàng)建新的task,可以使用已有的task
            //如果要啟動的activity的啟動模式是LAUNCH_SINGLE_INSTANCE,
            //則使用快速查找方法findTaskLocked,否則使用慢速查找方法findActivityLocked
            //因為如果啟動模式是LAUNCH_SINGLE_INSTANCE,則這個activity只會在一個單獨的Task里
            //故此查找時,可以以task為單位進行查找和比較,這樣比較快
            //查找得到的結果taskTop是相關task的棧頂?shù)腁ctivityRecord               
            // See if there is a task to bring to the front.  If this is
            // a SINGLE_INSTANCE activity, there can be one and only one
            // instance of it in the history, and it is always in its own
            // unique task, so we do a special search.
            ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                    ? findTaskLocked(intent, r.info)
                    : findActivityLocked(intent, r.info);
            //找到了相關task        
            if (taskTop != null) {
                //重設task的intent
                if (taskTop.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.
                    taskTop.task.setIntent(intent, r.info);
                }
                //如果目標task不在棧頂,
                //則先將Home task移動到棧頂(實際上只有當啟動Activity設置的Flag同時設置了
                //FLAG_ACTIVITY_TASK_ON_HOME和FLAG_ACTIVITY_NEW_TASK才會移動home task,
                //否則不會移動home task),
                //然后再將目標task移動到棧頂
                // If the target task is not in the front, then we need
                // to bring it to the front...  except...  well, with
                // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
                // to have the same behavior as if a new instance was
                // being started, which means not bringing it to the front
                // if the caller is not itself in the front.
                ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
                if (curTop != null && curTop.task != taskTop.task) {
                    r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                    boolean callerAtFront = sourceRecord == null
                            || curTop.task == sourceRecord.task;
                    if (callerAtFront) {
                        // We really do want to push this one into the
                        // user's face, right now.
                        movedHome = true;
                        moveHomeToFrontFromLaunchLocked(launchFlags);
                        moveTaskToFrontLocked(taskTop.task, r, options);
                        options = null;
                    }
                }
                //如果launchFlags設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,則會重置task 
                //從Launcher應用程序啟動應用會設置FLAG_ACTIVITY_RESET_TASK_IF_NEEDED       
                // If the caller has requested that the target task be
                // reset, then do so.
                if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                    taskTop = resetTaskIfNeededLocked(taskTop, r);
                }
                //... 一般情況下startFlags 不會設置 START_FLAG_ONLY_IF_NEEDED
                if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)  != 0) {
                    //...
                }
                // ==================================                                 
                //默認情況下不會設置 Intent.FLAG_ACTIVITY_CLEAR_TASK
                if ((launchFlags &
                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
                    // The caller has requested to completely replace any
                    // existing task with its new activity.  Well that should
                    // not be too hard...
                    reuseTask = taskTop.task;
                    performClearTaskLocked(taskTop.task.taskId);
                    reuseTask.setIntent(r.intent, r.info);
                } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                    //默認情況下launchFlags不會設置FLAG_ACTIVITY_CLEAR_TOP
                    //但是如果被啟動的activity的啟動模式是singleTask或者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.
                    //清除r所在的task 在r之上的所有activity, 
                    //該task里r和在r下的activity不會被清除
                    ActivityRecord top = performClearTaskLocked(
                            taskTop.task.taskId, r, launchFlags);
                    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(r.intent, r.info);
                        }
                        logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
                        top.deliverNewIntentLocked(callingUid, r.intent);
                    } else {
                        // A special case: we need to
                        // start the activity because it is not currently
                        // running, and the caller has asked to clear the
                        // current task to have this activity at the top.
                        addingToTask = true;
                        // Now pretend like this activity is being started
                        // by the top of its task, so it is put in the
                        // right place.
                        sourceRecord = taskTop;
                    }
                } else if (r.realActivity.equals(taskTop.task.realActivity)) {
                    // In this case the top activity on the task is the
                    // same as the one being launched, so we take that
                    // as a request to bring the task to the foreground.
                    // If the top activity in the task is the root
                    // activity, deliver this new intent to it if it
                    // desires.
                    if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
                            && taskTop.realActivity.equals(r.realActivity)) {
                        logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
                        if (taskTop.frontOfTask) {
                            taskTop.task.setIntent(r.intent, r.info);
                        }
                        taskTop.deliverNewIntentLocked(callingUid, r.intent);
                    } else if (!r.intent.filterEquals(taskTop.task.intent)) {
                        // In this case we are launching the root activity
                        // of the task, but with a different intent.  We
                        // should start a new instance on top.
                        addingToTask = true;
                        sourceRecord = taskTop;
                    }
                } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                    // In this case an activity is being launched in to an
                    // existing task, without resetting that task.  This
                    // is typically the situation of launching an activity
                    // from a notification or shortcut.  We want to place
                    // the new activity on top of the current task.
                    addingToTask = true;
                    sourceRecord = taskTop;
                } else if (!taskTop.task.rootWasReset) {
                    //進入該分支的情況比較少
                    // In this case we are launching in to an existing task
                    // that has not yet been started from its front door.
                    // The current task has been brought to the front.
                    // Ideally, we'd probably like to place this new task
                    // at the bottom of its stack, but that's a little hard
                    // to do with the current organization of the code so
                    // for now we'll just drop it.
                    taskTop.task.setIntent(r.intent, r.info);
                }   
                // ================================== end
                //如果沒有正在添加至某個Task, 并且不用加入一個已清除所有Activity的Task
                //此時只需要顯示棧頂Activity即可              
                if (!addingToTask && reuseTask == 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.
                    if (doResume) {
                        resumeTopActivityLocked(null, options);
                    } else {
                        ActivityOptions.abort(options);
                    }
                    return ActivityManager.START_TASK_TO_FRONT;
                }
            }
        }
    } 
    //...  
    if (r.packageName != null) {
        // 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.
        ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
        if (top != null && r.resultTo == null) {
            if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                if (top.app != null && top.app.thread != null) {
                    if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
                        //singleTop啟動模式或者singleTask啟動模式,
                        //并且task棧頂?shù)腶ctivity是要啟動的activity,則先顯示Activity
                        //然后調(diào)用該Activity的onNewIntent方法
                        logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
                        // For paranoia, make sure we have correctly
                        // resumed the top activity.
                        //先顯示Activity
                        if (doResume) {
                            resumeTopActivityLocked(null);
                        }
                        ActivityOptions.abort(options);
                        if ((startFlags&ActivityManager.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 ActivityManager.START_RETURN_INTENT_TO_CALLER;
                        }
                        //然后調(diào)用已顯示activity的onNewIntent方法
                        top.deliverNewIntentLocked(callingUid, r.intent);
                        return ActivityManager.START_DELIVERED_TO_TOP;
                    }
                }
            }
        }
    } else {
        if (r.resultTo != null) {
            sendActivityResultLocked(-1,
                    r.resultTo, r.resultWho, r.requestCode,
                Activity.RESULT_CANCELED, null);
        }
        ActivityOptions.abort(options);
        return ActivityManager.START_CLASS_NOT_FOUND;
    }
    boolean newTask = false;
    boolean keepCurTransition = false;
    // Should this be considered a new task?
    if (r.resultTo == null && !addingToTask
            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        if (reuseTask == null) {
             //創(chuàng)建新的task
            // todo: should do better management of integers.
            mService.mCurTask++;
            if (mService.mCurTask <= 0) {
                mService.mCurTask = 1;
            }
            r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in new task " + r.task);
        } else {
           //重復利用先前的task,該task里的所有acitivity已經(jīng)被清空
            r.setTask(reuseTask, reuseTask, true);
        }
        newTask = true;
        if (!movedHome) {
            moveHomeToFrontFromLaunchLocked(launchFlags);
        } 
    } else if (sourceRecord != null) {
        if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
            // In this case, we are adding the activity to an existing
            // task, but the caller has asked to clear that task if the
            // activity is already running.
            //清除r所在task在r之上的所有task,如果r不在task里,則返回的top為null
            ActivityRecord top = performClearTaskLocked(
                    sourceRecord.task.taskId, r, launchFlags);
            keepCurTransition = true;
            if (top != null) {
                logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
                //先調(diào)用onNewIntent方法 然后再顯示
                top.deliverNewIntentLocked(callingUid, r.intent);
                // For paranoia, make sure we have correctly
                // resumed the top activity.
                if (doResume) {
                    resumeTopActivityLocked(null);
                }
                ActivityOptions.abort(options);
                return ActivityManager.START_DELIVERED_TO_TOP;
            }
        } else if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
            //將棧里已有的activity移到棧頂
            // In this case, we are launching an activity in our own task
            // that may already be running somewhere in the history, and
            // we want to shuffle it to the front of the stack if so.
            int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
            if (where >= 0) {
                ActivityRecord top = moveActivityToFrontLocked(where);
                logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
                top.updateOptionsLocked(options);
                top.deliverNewIntentLocked(callingUid, r.intent);
                if (doResume) {
                    resumeTopActivityLocked(null);
                }
                return ActivityManager.START_DELIVERED_TO_TOP;
            }
        }
        // An existing activity is starting this new activity, so we want
        // to keep the new one in the same task as the one that is starting
        // it.
        //同一個應用程序里的Activity A和Activity B,A可跳轉至B,沒有設置taskAffinity
        //B的啟動模式為singleTask,從A跳轉至B時,B和A會在同一個task里
        //該情況下會執(zhí)行到這里的代碼,將B的task設置為和A一樣的task
        r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
        if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                + " in existing task " + r.task); 
    } 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.
        final int N = mHistory.size();
        ActivityRecord prev =
            N > 0 ? mHistory.get(N-1) : null;
        r.setTask(prev != null
                ? prev.task
                : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
        if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                + " in new guessed " + r.task);
    }  
    mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
            intent, r.getUriPermissionsLocked()); 
    if (newTask) {
        EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
    }
    logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
    startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    return ActivityManager.START_SUCCESS;
}
實際場景分析

實際場景1:

應用內(nèi)有兩個Activity,A和B,A為第應用入口Activity,從A可跳轉至B,A和B的啟動模式都為standard

1)從Launcher程序第1次啟動應用時的任務調(diào)度情況:

任務調(diào)度時會創(chuàng)建新task并將新的ActivityRecord加入這個新的task

2)然后跳轉至應用內(nèi)Activity時的任務調(diào)度情況:

任務調(diào)度時會將新的ActivityRecord加入已有的task

3)然后按Home鍵,再打開應用程序時的調(diào)度情況:

任務調(diào)度時會先找到已有的相關task,并顯示棧頂?shù)腁ctivity

1)從Launcher程序第1次啟動應用時

會創(chuàng)建新task并將新的ActivityRecord加入這個新的task,任務調(diào)度執(zhí)行如下所示:

final int startActivityUncheckedLocked(ActivityRecord r,
        ActivityRecord sourceRecord, int startFlags, boolean doResume,
        Bundle options) {
    //...
    //launchFlags為FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    int launchFlags = intent.getFlags();
   //... 
   //沒設置FLAG_ACTIVITY_PREVIOUS_IS_TOP,故此notTop為null        
    ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
            != 0 ? r : null;
   //startFlags未設置ActivityManager.START_FLAG_ONLY_IF_NEEDED
   //...  
   //sourceRecord為Launcher應用的Activity  launcher應用activity的啟動模式為singleTask
   // 故此下面的3個條件分支的內(nèi)容都不會執(zhí)行  
    if (sourceRecord == null) {
        //... 
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
         //...
    } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
        //... 
    }
    //... 
    //r.resultTo不為null, launchFlags設置了FLAG_ACTIVITY_NEW_TASK,需要將r.resultTo置為null
    if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        //... 
        r.resultTo = null;
    }         
    boolean addingToTask = false;
    boolean movedHome = false;
    TaskRecord reuseTask = null;
    //因為launchFlags為FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    //故此下面的條件會滿足, 也就是說只要從Launcher程序啟動應用,下面這個條件肯定會滿足
    if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //... 
        if (r.resultTo == null) {
            //因為應用被第一次啟動,故此找不到相關task,taskTop則為null
            ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                    ? findTaskLocked(intent, r.info)
                    : findActivityLocked(intent, r.info);
            if (taskTop != null) {
              //... 這里面的內(nèi)容不會執(zhí)行
            }     
        }
    }
   //...
   //r.packageName != null
    if (r.packageName != null) {
        //如果被啟動的Activity正好是棧頂?shù)腁ctivity,
        //并且被啟動的Activity啟動模式是singleTop或者singleTask,
        //則不用將新的ActivityRecord加入到棧里
        //top Activity為Launcher應用的Activity 
        ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
        if (top != null && r.resultTo == null) {
            //top.realActivity.equals(r.realActivity)不滿足
            if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                //... 這里的代碼不會被執(zhí)行 
            }
        }
    } else {
        //...
    } 
    boolean newTask = false;
    boolean keepCurTransition = false;
    // 此時 r.resultTo為null addingToTask為false  launchFlags設置了FLAG_ACTIVITY_NEW_TASK
    if (r.resultTo == null && !addingToTask
            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        if (reuseTask == null) {
            // todo: should do better management of integers.
            mService.mCurTask++;
            if (mService.mCurTask <= 0) {
                mService.mCurTask = 1;
            }
            //創(chuàng)建新task
            r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in new task " + r.task);
        } else {
           //...這里的代碼會執(zhí)行
        }
        newTask = true;
        if (!movedHome) {
            moveHomeToFrontFromLaunchLocked(launchFlags);
        }
    } else if (sourceRecord != null) {
         //... 這里的代碼不會被執(zhí)行
    } else {
       //...這里的代碼不會被執(zhí)行
    }
    //... 
    startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    return ActivityManager.START_SUCCESS;
}

2)跳轉至應用內(nèi)Activity時

會將新的ActivityRecord加入已有的task,任務調(diào)度執(zhí)行如下所示:

final int startActivityUncheckedLocked(ActivityRecord r,
        ActivityRecord sourceRecord, int startFlags, boolean doResume,
        Bundle options) {
    //此時launchFlags為0 
    int launchFlags = intent.getFlags();
    //notTop為null    
    ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
            != 0 ? r : null;
    //startFlags未設置ActivityManager.START_FLAG_ONLY_IF_NEEDED
    //...     
    if (sourceRecord == null) {
       //...這里的代碼不會被執(zhí)行
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
      //...這里的代碼不會被執(zhí)行   
    } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
      //...這里的代碼不會被執(zhí)行     
    }
    //r.resultTo != null 但是launchFlags未設置FLAG_ACTIVITY_NEW_TASK
    if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
       //... 這里的代碼不執(zhí)行  
    }
    boolean addingToTask = false;
    boolean movedHome = false;
    TaskRecord reuseTask = null;
    //launchFlags為0 r的啟動模式為standard 故此下面的邏輯都不會執(zhí)行
    if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //... 這里的代碼不執(zhí)行
    }
   //...
    if (r.packageName != null) {
        //top 是ActivityA 的ActivityRecord,
        //但是被啟動的Activity和top不是同一個Activity
        ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
        if (top != null && r.resultTo == null) {
            if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                 //...這里的代碼不執(zhí)行
            }
        }
    } else {
        //...這里的代碼不執(zhí)行
    }
    boolean newTask = false;
    boolean keepCurTransition = false;
    //此時 r.resultTo !=null  sourceRecord != null addingToTask=false
    if (r.resultTo == null && !addingToTask
            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        //...這里的代碼不執(zhí)行         
    } else if (sourceRecord != null) {
        if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
             //... 這里的代碼不執(zhí)行
        } else if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
             //... 這里的代碼不執(zhí)行 
        }
        //添加到現(xiàn)有的task 
        r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
        //... 
    } else {
        //... 這里的代碼不執(zhí)行 
    }
    //...
    return ActivityManager.START_SUCCESS;
}

3)然后按Home鍵,再打開應用程序

此時會先找到已有的相關task,并顯示棧頂?shù)腁ctivity,任務調(diào)度執(zhí)行如下所示:

final int startActivityUncheckedLocked(ActivityRecord r,
        ActivityRecord sourceRecord, int startFlags, boolean doResume,
        Bundle options) {
    //...
    //launchFlags為FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 
    int launchFlags = intent.getFlags();
    //notTop為null    
    ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
            != 0 ? r : null;
    //startFlags未設置ActivityManager.START_FLAG_ONLY_IF_NEEDED
    //...         
    if (sourceRecord == null) {
       //...這里的代碼不會被執(zhí)行
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //...這里的代碼不會被執(zhí)行  
    } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
       //...這里的代碼不會被執(zhí)行 
    }
    //此時 r.resultTo != null launchFlags設置了FLAG_ACTIVITY_NEW_TASK
    if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        //...
        r.resultTo = null;
    } 
    boolean addingToTask = false;
    boolean movedHome = false;
    TaskRecord reuseTask = null;
    //此時launchFlags設置了FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 
    if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //此時 r.resultTo == null
        if (r.resultTo == null) {
            //此時已有相關task,并且task 棧的棧頂是Activity B的ActivityRecord
            //故此taskTop為Activity B的ActivityRecord 
            ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                    ? findTaskLocked(intent, r.info)
                    : findActivityLocked(intent, r.info);
            if (taskTop != null) {
                //... 
                // 此時curTop是Launcher應用的Activity的ActivityRecord  
                ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
                if (curTop != null && curTop.task != taskTop.task) {
                    r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                    //此時Launcher應用的task在棧頂,故此callerAtFront為true,
                    //此時會把被啟動的應用的task移至棧頂
                    boolean callerAtFront = sourceRecord == null
                            || curTop.task == sourceRecord.task;
                    if (callerAtFront) {
                        // We really do want to push this one into the
                        // user's face, right now.
                        movedHome = true;
                        moveHomeToFrontFromLaunchLocked(launchFlags);
                        moveTaskToFrontLocked(taskTop.task, r, options);
                        options = null;
                    }
                }
                //此時launchFlags設置了FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                //此時需要重置task 重置完后 taskTop為ActivityB的ActivityRecord   
                if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                    taskTop = resetTaskIfNeededLocked(taskTop, r);
                }
                //startFlags為0
                if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)  != 0) {
                    //... 這些代碼都不會被執(zhí)行 
                } 
                //根據(jù)launchFlags和被啟動的activity的信息 設置resueTask addingTask變量的值                  
                //沒設置 Intent.FLAG_ACTIVITY_CLEAR_TASK
                if ((launchFlags &
                          (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
                          == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
                      //... 這些代碼都不會被執(zhí)行  
                 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                          || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
                          || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                      //... 這些代碼都不會被執(zhí)行  
                 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
                      //... 這些代碼都不會被執(zhí)行   
                 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                       //因為從Launcher程序啟動時launchFlags設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                       //所以不會進入該分支
                       //... 這些代碼都不會被執(zhí)行   
                  } else if (!taskTop.task.rootWasReset) {
                       //... 這些代碼都不會被執(zhí)行    
                  }  
                  //此時addingToTask為false,reuseTask為null,故此顯示棧頂Actvity即可
                  if (!addingToTask && reuseTask == 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.
                      if (doResume) {
                          resumeTopActivityLocked(null, options);
                      } else {
                          ActivityOptions.abort(options);
                      }
                      return ActivityManager.START_TASK_TO_FRONT;
                  } 
            }
        }
    }
   //... 以下代碼都不會被執(zhí)行    
}
實際場景2:

應用內(nèi)有兩個Activity,A和B,A為第應用入口Activity,從A可跳轉至B,A的啟動模式都為standard,B的啟動模式為singleTop

此時已從Launchenr程序打開應用,啟動了Actvity A,再從A跳轉至B,此時的任務調(diào)度情況:

此時不會創(chuàng)建新的Task,而是將B的ActivityRecord加入到A所在的task里

任務調(diào)度執(zhí)行如下所示:

final int startActivityUncheckedLocked(ActivityRecord r,
        ActivityRecord sourceRecord, int startFlags, boolean doResume,
        Bundle options) {
    //...  
    //此時launcheFlags為0
    int launchFlags = intent.getFlags();      
    //notTop為null
    ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
            != 0 ? r : null;
    //默認情況下startFlags不會設置START_FLAG_ONLY_IF_NEEDED    
    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
        //...這里的代碼不會執(zhí)行
    }    
    //r.launchMode = ActivityInfo.LAUNCH_SINGLE_TASK 
    if (sourceRecord == null) {
       //這里的代碼不會執(zhí)行  
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //這里的代碼不會執(zhí)行    
    } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }
    //此時r.resultTo!=null launchFlags設置了Intent.FLAG_ACTIVITY_NEW_TASK
    if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
       //...
        r.resultTo = null;
    }       
    //addingToTask如果為true表示正在添加至某個task,后續(xù)需要將r添加至sourceRecord所在的task
    boolean addingToTask = false;
    //movedHome表示是否移動home task
    boolean movedHome = false; 
    TaskRecord reuseTask = null;       
    if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        //此時 r.resultTo = null
        if (r.resultTo == null) {
            //此時找到的taskTop是Activity A的ActivityRecord,
            //因為Actvity B和A的ActivityRecord所在的Task是相關的
            ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                    ? findTaskLocked(intent, r.info)
                    : findActivityLocked(intent, r.info);
            //找到了相關task        
            if (taskTop != null) {
                //重設task的intent
                if (taskTop.task.intent == null) {
                     //...
                }
                //此時找到的task已在棧頂
                ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
                if (curTop != null && curTop.task != taskTop.task) {
                    //... 這里的代碼不會執(zhí)行 
                }
                //launchFlags為0
                if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                    taskTop = resetTaskIfNeededLocked(taskTop, r);
                }
                //... 一般情況下startFlags 不會設置 START_FLAG_ONLY_IF_NEEDED
                if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)  != 0) {
                    //...
                } 
                // ==================== begin
                // launchFlags此時為0
                if ((launchFlags &
                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
                     //...這里的代碼不執(zhí)行
                } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                    // r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
                    // 故此會進入該分支
                    //因為B還從未啟動,故此得到的top為null
                    ActivityRecord top = performClearTaskLocked(
                            taskTop.task.taskId, r, launchFlags);
                    if (top != null) {
                        //...這里的代碼不執(zhí)行 
                    } else { 
                        addingToTask = true; 
                        sourceRecord = taskTop;
                    }
                } else if (r.realActivity.equals(taskTop.task.realActivity)) {
                     //...這里的代碼不執(zhí)行 
                } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                     //...這里的代碼不執(zhí)行 
                } else if (!taskTop.task.rootWasReset) {
                     //...這里的代碼不執(zhí)行 
                }
                // ==================== end     
                // 此時 addingToTask為true          
                if (!addingToTask && reuseTask == null) {
                     //...這里的代碼不執(zhí)行 
                }
            }
        }
    } 
    //... 
    if (r.packageName != null) { 
        ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
        if (top != null && r.resultTo == null) {
            //此時task還沒有B的ActivityRecord,故此不會進入下述分支
            if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                 //...這里的代碼不執(zhí)行
            }
        }
    } else {
           //...這里的代碼不執(zhí)行
    }
    boolean newTask = false;
    boolean keepCurTransition = false;
    // 此時 r.resultTo == null addingToTask為true sourceRecord != null
    if (r.resultTo == null && !addingToTask
            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
         //...這里的代碼不執(zhí)行 
    } else if (sourceRecord != null) {
        if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
               //...這里的代碼不執(zhí)行 
        } else if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
               //...這里的代碼不執(zhí)行 
        }
        //將B的ActivityRecord加入A的ActivityRecord所在的Task里 
        r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
        //... 
    } else {
         //...這里的代碼不執(zhí)行
    }
    //...
    startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    return ActivityManager.START_SUCCESS;
}

總結

從上面的分析可以看出來,Activity和Task的調(diào)度算法非常復雜,需結合實際場景才好分析,只有這樣才知道是否需要新建Task,還是將新的ActivityRecord加入到已有的Task里,不過我們?nèi)绻芾斫鈫幽J降囊恍┨攸c,對理解調(diào)度算法會有很大幫助。

大家可以結合下述場景分析調(diào)度算法:

1.從通知欄啟動Activity:

假設應用有Activity A ,Activity A已啟動,

此時發(fā)了一個通知,該通知用于啟動Activity A,啟動Activity A時不加任何特殊flag

點擊通知,針對以下情況對任務調(diào)度情況進行分析:

  1. Activity A的啟動模式為standard

  2. Activity A的啟動模式為singleTop

  3. Activity A的啟動模式為singleTask

  4. Activity A的啟動模式為singleInstance

2.跨應用跳轉Activity

假設應用app1有一個Activity A,另一個應用app2有一個Activity B

Activity A可跳轉至Activity B

因為Activity A和Actiivty B在不同應用,所以Activity的taskffinity必然不同

現(xiàn)在Activity A已啟動,跳轉至Activity B,

針對以下4種情況分析跳轉之后的Activity Task情況

  1. Activity B的啟動模式為standard

  2. Activity B的啟動模式為singleTop

  3. Activity B的啟動模式為singleTask

  4. Activity B的啟動模式為singleInstance

如果大家對上述場景分析有興趣的話,可以在評論里一起探討結果。

轉載至

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容