Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> AMS分析--基於深入理解android(2)

AMS分析--基於深入理解android(2)

編輯:關於Android編程

final int startActivityUncheckedLocked(ActivityRecord r,
            ActivityRecord sourceRecord, int startFlags, boolean doResume,
            Bundle options) {
        final Intent intent = r.intent;
        final int callingUid = r.launchedFromUid;

        int launchFlags = intent.getFlags();

        /// M: AMS log enhancement @{
        if (!ActivityManagerService.IS_USER_BUILD)
            Slog.i(TAG, "ACT-launchFlags(original): 0x" + Integer.toHexString(launchFlags) + ", launchMode:" + r.launchMode
                + ", startFlags: " + startFlags + ", doResume:" + doResume);
        /// @}

        // We'll invoke onUserLeaving before onPause only if the launching
        // activity did not explicitly state that this is an automated launch.
        mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;//加上FLAG_ACTIVITY_NO_USER_ACTION這個標志,系統就不會調用onUserLeaveHint
        //比如用戶主動切換任務,短按home進入桌面等會調用onUserLeaveHint,系統自動切花activity不會調用此方法,如來電,滅屏等

android onUserLeaveHint和onUserInteraction

onUserLeaveHint 當用戶的操作使一個activity准備進入後台時,此 方法會像activity的生命周期的一部分被調用。例如,當用戶按下 Home鍵,
Activity#onUserLeaveHint()將會被回調。但是當來電導致來電activity自動占據前台,Activity#onUserLeaveHint()將不會被回調。

onUserLeaveHint() 用戶手動離開當前activity,會調用該方法,比如用戶主動切換任務,短按home進入桌面等。系統自動切換activity不會調用此方法,如來電,滅屏等。

onUserInteraction() activity在分發各種事件的時候會調用該方法,注意:啟動另一個activity,Activity#onUserInteraction()會被調用兩次,一次是activity捕獲到事件,另一次是調用Activity#onUserLeaveHint()之前會調用Activity#onUserInteraction()。

  if (!doResume) {
            r.delayedResume = true;//還沒有恢復的app  switch
        }
            //啟動Activity時默認不會設置FLAG_ACTIVITY_PREVIOUS_IS_TOP 
    //故此notTop默認情況下會是null
        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
       if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
            //ActivityRecord checkedCaller優先等於sourceRecord,其次選擇正在運行的Activity
            //如果調用者和被啟動的對象是同一個,不不需要重復啟動 所以START_FLAG_ONLY_IF_NEEDED 可以置位空
            ActivityRecord checkedCaller = sourceRecord;
            if (checkedCaller == null) {
                checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);
            }
            if (!checkedCaller.realActivity.equals(r.realActivity)) {
                // Caller is not the same as launcher, so always needed.//調用者和啟動這不一致,所以是啟動必須的,置位意思非必須的
                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
            }
        }
   //根據sourceRecord的情況進行對應處理,能理解下面這段if/else的判斷語句嗎
   if(sourceRecord == null) {
      //如果請求的發起者為空,則當然需要新建一個Task
      if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0)
         launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
   }else if (sourceRecord.launchMode ==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
      //如果sourceRecord單獨占一個Instance,則新的Activity必然處於另一個Task中
     launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
   } else if(r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
               || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
      //如果啟動模式設置了singleTask或singleInstance,則也要創建新Task
      launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
   }//if(sourceRecord== null)判斷結束
  ActivityInfo newTaskInfo = null;
        Intent newTaskIntent = null;
        final ActivityStack sourceStack;
        if (sourceRecord != null) {
            if (sourceRecord.finishing) {

                //如果sourceRecord已經處於finishing狀態,那麼他所在的Task就很有可能已經為空或者即將為空。
                //我們就不能盲目throw it in to that task。
                if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
                    newTaskInfo = sourceRecord.info;
                    newTaskIntent = sourceRecord.task.intent;
                }
                sourceRecord = null;
                sourceStack = null;
            } else {
                sourceStack = sourceRecord.task.stack;
            }
        } else {
            sourceStack = null;
        }
        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            //如果啟動的activity需要新的task,那麼新啟動的activity將會與其caller斷開依賴關系
            //,這個關系主要是指result反饋,A-->B,如果A是通過startActivityForResult()請求啟動的,並且requestCode >=0,那麼如果B是在新的task中
            //,那麼B在finish的時候將不再向A反饋result,而是在啟動過程中就會向A反饋一個RESULT_CANCELED。

            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
            r.resultTo.task.stack.sendActivityResultLocked(-1,
                    r.resultTo, r.resultWho, r.requestCode,
                Activity.RESULT_CANCELED, null);
            r.resultTo = null;
        }//禁止兩個task之間通信,發送取消發送結果消息給調用者
  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,所以r.resultTo 必須被以上函數設置為null

                ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                        ? findTaskLocked(r)//從所有Stack中的所有Task中的Activity中查找看能否找到要啟動的Activity,根據要啟動的Activity啟動模式是否是SingleInstance所采用的搜索方法是不一樣的。  
                        : findActivityLocked(intent, r.info);
                if (intentActivity != null) {
                    if (r.task == null) {
                        r.task = intentActivity.task;
                    }
                    targetStack = intentActivity.task.stack;
                    targetStack.mLastPausedActivity = null;
                    if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
                            + " from " + intentActivity);
                    moveHomeStack(targetStack.isHomeStack());//rus啟動桌面
                    if (intentActivity.task.intent == null) {

                        intentActivity.task.setIntent(intent, r.info);

以下3種條件需要檢查是否有有task可復用

⑴ (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

第⑴是一個組合條件,Intent.FLAG_ACTIVITY_MULTIPLE_TASK不能單獨使用,它是和Intent.FLAG_ACTIVITY_NEW_TASK結合起來使用的,如果設置了Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那麼將會永遠啟動一個新的task,不管是否有可復用的task。

為什麼是這3種條件,從android的開發文檔中,我們可知LAUNCH_SINGLE_TASK和LAUNCH_SINGLE_INSTANCE兩種launch mode的activity只允許作為task的root activity,既然是作為root activity,那麼它所處的task的affinity必然是和它的是一樣的,因此從mHistory中找打一個和自己的affinity相同的task是非常有必要的。

而對於設置了Intent.FLAG_ACTIVITY_NEW_TASK的Intent來說,並且沒有設置Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那麼同樣的,它也必須是作為它所處的task的root activity。道理是一樣的。

AMS去mHistory中查找可復用的task,查找這個task的規則如下:    

⑴ launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE的情況,遵循如下規則: @findTaskLocked()

    ① 查找mHistory中是否有與要啟動的activity相同affinity的task,上面也提過這幾類activity啟動時,均是作為task的root activity,並且其task的affinity必須和自己的affinity相同,因此首先需要去mHistory查找和自己affinity相同的task。

    ② 如果activity沒有affinity,即屬性android:taskAffinity設置為“”,空字符串時。此時AMS就會去mHistory中去查找是否有task的root activity和啟動的activity相同,通過比較task.intent.getComponent()和啟動activity的Comeponent比較,為什麼是root activity,前面分析過了;

    ③ 如果task.Intent為空,這種情況發生在TaskReparenting之後,TaskReparenting之後,AMS為這個activity創建一個新的task,並將啟動這個activity的Intent賦值給task.affinityIntent,並且此時的task.Intent==null。此時就需要比較task.affinityIntent.getComponent()和啟動activity的Comeponent比較,看是否和啟動的activity相同。

以上3個規則中,均是返回找的task中最上面的activity,而不一定是task的activity,至於如何處理要啟動的activity和task中已有的activity,後面會介紹。

⑵ launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE的情況,遵循如下規則: @findActivityLocked()

對於ActivityInfo.LAUNCH_SINGLE_INSTANCE啟動模式來說,它所處的task中只允許有它一個activity,因此它的規則只符合上面規則中的②;

對於第①條,由於設置了ActivityInfo.LAUNCH_SINGLE_INSTANCE啟動模式的activity,它只能自己獨處一個task,不可能和別人共享同一個task,因此mHistory即使存在了與該activity有相同的affinity的activity,如果這個activity和啟動的activity不同,那麼ActivityInfo.LAUNCH_SINGLE_INSTANCE啟動模式的activity也不可能和它共用一個task,因此這第①條完全可以不用檢查。

對於第②條,由於該模式的activity獨處一個task,因此完全沒有可能所處的task的affinity和自己的affinity不同,因此,假如mHistory存在相同的activity與啟動的activity相同,那麼這個activity的affinity必然和自己的相同。所以對於這種模式,第②條囊括了其他模式的①②兩條。

對於第③條,同樣的道理,ActivityInfo.LAUNCH_SINGLE_INSTANCE啟動模式的activity不可能處在與自己不同affinity的task中,因此不可能出現TaskReparenting操作,所以這條也不需要。

+++++++++++++++++

什麼是Affinity

       在某些情況下,Android需要知道一個Activity屬於哪個Task,即使它沒有被啟動到一個具體的Task裡。這是通過任務共用性(Affinities)完成的。任務共用性(Affinities)為這個運行一個或多個Activity的Task提供了一個獨特的靜態名稱,默認的一個活動的任務共用性(Affinity)是實現了該Activity的.apk包的名字。

       當開始一個沒有Intent.FLAG_ACTIVITY_NEW_TASK標志的Activity時,任務共用性affinities不會影響將會運行該新活動的Task:它總是運行在啟動它的Task裡。但是,如果使用了NEW_TASK標志,那麼共用性(affinity)將被用來判斷是否已經存在一個有相同共用性(affinity)的Task。如果是這樣,這項Task將被切換到前面而新的Activity會啟動於這個Task的頂層。

       這種特性在您必須使用NEW_TASK標志的情況下最有用,尤其是從狀態欄通知或桌面快捷方式啟動活動時。結果是,當用戶用這種方式啟動您的應用程序時,它的當前Task將被切換到前台,而且想要查看的Activity被放在最上面。

       你可以在程序清單(Manifest)文件的應用程序application標簽中為.apk包中所有的活動分配你自己的任務共用性Affinites,或者在活動標記中為各個活動進行分配。

       一些說明其如何使用的例子如下:


如果您的.apk包含多個用戶可以啟動的高層應用程序,那麼您可能需要對用戶看到的每個Activity(活動)指定不同的affinities。一個不錯的命名慣例是以附加一個以冒號分隔的字符串來擴展您的.apk包名。例如,“ com.android.contacts ”.apk可以有affinities:“com.android.contacts:Dialer”和“ com.android.contacts:ContactsList”。
如果您正在替換一個通知,快捷方式,或其他可以從外部發起的應用程序的“內部”活動,你可能需要明確設定您替代活動的taskAffinity和您准備替代的應用程序一樣。例如,如果您想替換contacts詳細信息視圖(用戶可以創建並調用快捷方式),你得把taskAffinity設置成“com.android.contacts”。

        跟 Task 有關的 manifest文件中Activity的特性值介紹

        android:allowTaskReparenting 
        用來標記Activity能否從啟動的Task移動到有著affinity的Task(當這個Task進入到前台時)
       “true”,表示能移動,“false”,表示它必須呆在啟動時呆在的那個Task裡。

       如果這個特性沒有被設定,設定到元素上的allowTaskReparenting特性的值會應用到Activity上。默認值為“false”。
       一般來說,當Activity啟動後,它就與啟動它的Task關聯,並且在那裡耗盡它的整個生命周期。當當前的Task不再顯示時,你可以使用這個特性來強制Activity移動到有著affinity的Task中。典型用法是:把一個應用程序的Activity移到另一個應用程序的主Task中。 
       例如,如果 email中包含一個web頁的鏈接,點擊它就會啟動一個Activity來顯示這個頁面。這個Activity是由Browser應用程序定義的,但是,現在它作為email Task的一部分。如果它重新宿主到Browser Task裡,當Browser下一次進入到前台時,它就能被看見,並且,當email Task再次進入前台時,就看不到它了。 
       Actvity的affinity是由taskAffinity特性定義的。Task的affinity是通過讀取根Activity的affinity決定。因此,根Activity總是位於相同affinity的Task裡。由於啟動模式為“singleTask”和“singleInstance”的Activity只能位於Task的底部,因此,重新宿主只能限於“standard”和“singleTop”模式。

       android:alwaysRetainTaskState

       用來標記Activity所在的Task的狀態是否總是由系統來保持。
      “true”,表示總是;“false”,表示在某種情形下允許系統恢復Task到它的初始化狀態。默認值是“false”。
       這個特性只針對Task的根Activity有意義;對其它Activity來說,忽略之。 
       一般來說,特定的情形如當用戶從主畫面重新選擇這個Task時,系統會對這個Task進行清理(從stack中刪除位於根Activity之上的所有Activivity)。典型的情況,當用戶有一段時間沒有訪問這個Task時也會這麼做,例如30分鐘。 
       然而,當這個特性設為“true”時,用戶總是能回到這個Task的最新狀態,無論他們是如何啟動的。這非常有用,例如,像Browser應用程序,這裡有很多的狀態(例如多個打開的Tab),用戶不想丟失這些狀態。

       android:clearTaskOnLaunch

       用來標記是否從Task中清除所有的Activity,除了根Activity外(每當從主畫面重新啟動時)
      “true”,表示總是清除至它的根Activity,“false”表示不。默認值是“false”。
        這個特性只對啟動一個新的Task的Activity(根Activity)有意義;對Task中其它的Activity忽略。 
        當這個值為“true”,每次用戶重新啟動這個Task時,都會進入到它的根Activity中,不管這個Task最後在做些什麼,也不管用戶是使用BACK還是HOME離開的。當這個值為“false”時,可能會在一些情形下(參考alwaysRetainTaskState特性)清除Task的Activity,但不總是。

       假設,某人從主畫面啟動了Activity P,並從那裡遷移至Activity Q。接下來用戶按下HOME,然後返回Activity P。一般,用戶可能見到的是Activity Q,因為它是P的Task中最後工作的內容。然而,如果P設定這個特性為“true”,當用戶按下HOME並使這個Task再次進入前台時,其上的所有的Activity(在這裡是Q)都將被清除。因此,當返回到這個Task時,用戶只能看到P。

       如果這個特性和allowTaskReparenting都設定為“true”,那些能重新宿主的Activity會移動到共享affinity的Task中;剩下的Activity都將被拋棄,如上所述。 

       android:finishOnTaskLaunch 

       用來標記當用戶再次啟動它的Task(在主畫面選擇這個Task)時已經存在的Activity實例是否要關閉(結束)
     “true”,表示應該關閉,“false”表示不關閉。默認值是“false”。 
       如果這個特性和allowTaskReparenting都設定為“true”,這個特性勝出。Activity的affinity忽略。這個Activity不會重新宿主,但是會銷毀。 


 跟 Task 有關的 Intent對象中設置的Flag

       FLAG_ACTIVITY_BROUGHT_TO_FRONT 

       這個標志一般不是由程序代碼設置的,如在launchMode中設置singleTask模式時系統幫你設定。 

       FLAG_ACTIVITY_CLEAR_TOP 

       如果設置,並且這個Activity已經在當前的Task中運行,因此,不再是重新啟動一個這個Activity的實例,而是在這個Activity上方的所有Activity都將關閉,然後這個Intent會作為一個新的Intent投遞到老的Activity(現在位於頂端)中。 
       例如,假設一個Task中包含這些Activity:A,B,C,D。如果D調用了startActivity(),並且包含一個指向Activity B的Intent,那麼,C和D都將結束,然後B接收到這個Intent,因此,目前stack的狀況是:A,B。 
       上例中正在運行的Activity B既可以在onNewIntent()中接收到這個新的Intent,也可以把自己關閉然後重新啟動來接收這個Intent。如果它的啟動模式聲明為“multiple”(默認值),並且你沒有在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標志,那麼它將關閉然後重新創建;對於其它的啟動模式,或者在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標志,都將把這個Intent投遞到當前這個實例的onNewIntent()中。 
       這個啟動模式還可以與FLAG_ACTIVITY_NEW_TASK結合起來使用:用於啟動一個Task中的根Activity,它會把那個Task中任何運行的實例帶入前台,然後清除它直到根Activity。這非常有用,例如,當從Notification Manager處啟動一個Activity。

       FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET

       如果設置,這將在Task的Activity stack中設置一個還原點,當Task恢復時,需要清理Activity。也就是說,下一次Task帶著FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標記進入前台時(典型的操作是用戶在主畫面重啟它),這個Activity和它之上的都將關閉,以至於用戶不能再返回到它們,但是可以回到之前的Activity。 
       這在你的程序有分割點的時候很有用。例如,一個e-mail應用程序可能有一個操作是查看一個附件,需要啟動圖片浏覽Activity來顯示。這個Activity應該作為e-mail應用程序Task的一部分,因為這是用戶在這個Task中觸發的操作。然而,當用戶離開這個Task,然後從主畫面選擇e-mail app,我們可能希望回到查看的會話中,但不是查看圖片附件,因為這讓人困惑。通過在啟動圖片浏覽時設定這個標志,浏覽及其它啟動的Activity在下次用戶返回到mail程序時都將全部清除。

       FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

       如果設置,新的Activity不會在最近啟動的Activity的列表中保存。

       FLAG_ACTIVITY_FORWARD_RESULT

       如果設置,並且這個Intent用於從一個存在的Activity啟動一個新的Activity,那麼,這個作為答復目標的Activity將會傳到這個新的Activity中。這種方式下,新的Activity可以調用setResult(int),並且這個結果值將發送給那個作為答復目標的Activity。

       FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY

       這個標志一般不由應用程序代碼設置,如果這個Activity是從歷史記錄裡啟動的(常按HOME鍵),那麼,系統會幫你設定。

       FLAG_ACTIVITY_MULTIPLE_TASK

       不要使用這個標志,除非你自己實現了應用程序啟動器。與FLAG_ACTIVITY_NEW_TASK結合起來使用,可以禁用把已存的Task送入前台的行為。當設置時,新的Task總是會啟動來處理Intent,而不管這是是否已經有一個Task可以處理相同的事情。 
       由於默認的系統不包含圖形Task管理功能,因此,你不應該使用這個標志,除非你提供給用戶一種方式可以返回到已經啟動的Task。 
       如果FLAG_ACTIVITY_NEW_TASK標志沒有設置,這個標志被忽略。

       FLAG_ACTIVITY_NEW_TASK

       如果設置,這個Activity會成為歷史stack中一個新Task的開始。一個Task(從啟動它的Activity到下一個Task中的Activity)定義了用戶可以遷移的Activity原子組。Task可以移動到前台和後台;在某個特定Task中的所有Activity總是保持相同的次序。 
       這個標志一般用於呈現“啟動”類型的行為:它們提供用戶一系列可以單獨完成的事情,與啟動它們的Activity完全無關。 
       使用這個標志,如果正在啟動的Activity的Task已經在運行的話,那麼,新的Activity將不會啟動;代替的,當前Task會簡單的移入前台。參考FLAG_ACTIVITY_MULTIPLE_TASK標志,可以禁用這一行為。 
       這個標志不能用於調用方對已經啟動的Activity請求結果。

        FLAG_ACTIVITY_NO_ANIMATION

        如果在Intent中設置,並傳遞給Context.startActivity()的話,這個標志將阻止系統進入下一個Activity時應用Acitivity遷移動畫。這並不意味著動畫將永不運行——如果另一個Activity在啟動顯示之前,沒有指定這個標志,那麼,動畫將被應用。這個標志可以很好的用於執行一連串的操作,而動畫被看作是更高一級的事件的驅動。

       FLAG_ACTIVITY_NO_HISTORY

       如果設置,新的Activity將不再歷史stack中保留。用戶一離開它,這個Activity就關閉了。這也可以通過設置noHistory特性。

       FLAG_ACTIVITY_NO_USER_ACTION 

       如果設置,作為新啟動的Activity進入前台時,這個標志將在Activity暫停之前阻止從最前方的Activity回調的onUserLeaveHint()。 
       典型的,一個Activity可以依賴這個回調指明顯式的用戶動作引起的Activity移出後台。這個回調在Activity的生命周期中標記一個合適的點,並關閉一些Notification。 
       如果一個Activity通過非用戶驅動的事件,如來電或鬧鐘,啟動的,這個標志也應該傳遞給Context.startActivity,保證暫停的Activity不認為用戶已經知曉其Notification。 

        FLAG_ACTIVITY_REORDER_TO_FRONT

       如果在Intent中設置,並傳遞給Context.startActivity(),這個標志將引發已經運行的Activity移動到歷史stack的頂端。 
       例如,假設一個Task由四個Activity組成:A,B,C,D。如果D調用startActivity()來啟動Activity B,那麼,B會移動到歷史stack的頂端,現在的次序變成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP標志也設置的話,那麼這個標志將被忽略。 

       FLAG_ACTIVITY_SINGLE_TOP

       如果設置,當這個Activity位於歷史stack的頂端運行時,不再啟動一個新的。

+++++++++++++++++++

        // if the caller is not itself in the front.
                    final ActivityStack lastStack = getLastStack();
                    ActivityRecord curTop = lastStack == null?
                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);//檢測當前在堆棧頂端的Activity是否就是即將要啟動的Activity
                    /* 這段代碼的邏輯是看一下,當前在堆棧頂端的Activity是否就是即將要啟動的Activity,有些情況下,如果即將要啟動的Activity就在堆棧的頂端,*/
                    /*那麼,就不會重新啟動這個Activity的別一個實例了,*/
                    /*現在處理堆棧頂端的Activity是Launcher,與我們即將要啟動的MainActivity不是同一個Activity,因此,這裡不用進一步處理上述介紹的情況*/
                    if (curTop != null && (curTop.task != intentActivity.task ||
                            curTop.task != lastStack.topTask())) {
   //當 notTop !=null ,此時有可能 curTop.task != lastStack.topTask                     r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);//因為系統中存在這個Activity,所以把它拿到前台。不新建
                        //可以參考這篇/kf/201407/319948.html
                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
                                sourceStack.topActivity().task == sourceRecord.task)) {
                            // We really do want to push this one into the
                            // user's face, right now.
                            movedHome = true;//movedHome表示是否移動home task
                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
                            //這一步,將已經存在的我們的目標Task終於被移動到了前台!參數intentActivity.task就是我們搜索出來的我們要啟動
                            //的Activity所在的Task,r就是我們要啟動的ActivityRecord。
                            if ((launchFlags &
                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                // Caller wants to appear on home activity.
                                intentActivity.task.mOnTopOfHome = true;//把當前新啟動的任務置於Home任務之上,也就是按back鍵從這個任務返回的時候會回到home
                                //,即使這個不是他們最後看見的activity
                            }
                            options = null;
                            /// M: Fix ALPS01276300, at this case, avoid move home to top when resume top @{
                            intentActivity.task.mMovingToFront = true;
                            /// @}
                        }

Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP
檢查Intent是否設置了Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,這個標志我有點困惑,從它的注釋可以看出它的含義是指如果設置了該flag,那麼mHistory中最top的activity在後續的處理中將不被視為top,而將前一個activity視為top,如A–>B–>C,將B視為top。
這個top activity的作用很大,涉及到後面對task的處理。但是目前來看這個flag並沒有起到該有的作用,代碼中判斷如果設置了該標志,那麼AMS將會視當前正在啟動的activity為top,然後去mHistory中去查找它的前一個activity為後續task處理的top activity(topRunningNonDelayedActivityLocked()中實現),但是現在的問題是此時此刻,正在啟動的activity並不存在於mHistory中,因為我們在前一個函數中剛剛創建了這個ActivityRecord。如下面代碼所示:
[java] view plaincopy
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
因此,感覺這個flag的意義不是太大

      // If the caller has requested that the target task be
                    // reset, then do so.
                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
                    }
                    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!  And for paranoia, make
                        // sure we have correctly resumed the top activity.
                        if (doResume) {
                        //默認情況下startFlags不會設置START_FLAG_ONLY_IF_NEEDED,調用者和啟動這不一致,所以是啟動必須的,置位意思非必須的
                            resumeTopActivitiesLocked(targetStack, null, options);
                        } else {
                            ActivityOptions.abort(options);
                        }
                        /// M: Add debug task message @{
                        if (DEBUG_TASKS) {
                            Slog.i(TAG, "START_RETURN_INTENT_TO_CALLER, doResume = " + doResume);
                        }
                        /// @}
                        if (r.task == null)  Slog.v(TAG,
                                "startActivityUncheckedLocked: task left null",
                                new RuntimeException("here").fillInStackTrace());
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:如果設置該屬性,並且這個activity在一個新的task中正在被啟動或者被帶到一個已經存在的task的頂部,這時這個activity將會被作為這個task的首個頁面加載。這將會導致擁有這個應用的affinities的task處於一個合適的狀態(移動activity到這個task或者activity從中移出),或者簡單的重置這個task到它的初始狀態

http://blog.csdn.net/windskier/article/details/7096521
Reset Task
如果Intent設置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,最常見的情況,當從Home啟動應用程序時,會設置這個flag;從recently task進入應用程序,則不會設置這個falg。
設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,AMS會對復用的task作如下處理,下面稱這個可復用的task為復用task:
⑴ mHistory中,對於復用task中的除root activity外的activity,有如下處理
在此之前,先介紹activity的幾個關鍵屬性:
① 如果復用task在後台時間超過30min,那麼在這個過程中將刪除除root activity之外的所有的activity;
② 如果新啟動的activity設置了屬性ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE,那麼表明它並不要求後台20min的復用task刪除activity;
③ 如果新啟動的activity設置了屬性ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH,那麼表明不論復用task在後台是否超過30min,一律要求刪除除root activity之外的所有的activity;
④ 復用task中的activity設置了屬性ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH,那麼復用task從home中再次被啟動到前台時,這個activity會被刪除;
⑤ 復用task中的activity設置了屬性ActivityInfo.FLAG_ALLOW_TASK_REPARENTIN,並且這個activity的resultTo為空,那麼也就是說這個activity和它的caller沒有依賴關系,那麼AMS認為這個activity暫時沒有用處了,需要對其進行TaskReparenting操作,最好的方法是把它放到mHistory棧底,不影響其他task。
⑥ 復用task中的activity的Intent設置屬性Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那麼下次再從home中進入到task中,那麼將刪除設置了該屬性的activity以上所有的activity,例如A–>B–>C–>D–>E,加入在C啟動D時設置了該屬性,那麼下次從HOME中再次進入到這個task中時,將會是A–>B–>C。
⑦ 如果復用task中的activity的resultTo不為空,也就是啟動這個activity的是一個activity,那麼這個activity的處理將按照它的前一個activity的處理方式來處理,不管在何時情況下,它的前一個activity都是啟動它的activity,即便resultTo不是前一個activity,如設置了Intent.FLAG_ACTIVITY_FORWARD_RESULT。如果復用task中每個activity的resultTo都不為空,並且上述處理優先級在其前面的屬性沒有設置的話,那麼這個復用task中的activity將不作任何的處理。
一般情況下,activity的resultTo都不為空,除非設置了Intent.FLAG_ACTIVITY_FORWARD_RESULT,那麼此時被啟動的activity的caller的resultTo將會為空。
task中的activity的屬性設置是上述屬性的組合,因此reset task過程要按照一定的優先級來處理,上述屬性的處理優先級是:⑥=④>⑦>⑤>③=②>①
具體操作順序如下:
? 根據⑥,④條件來刪除復用task中相應的activity;
? ⑦條件下,將會暫時不做處理,再根據它的前一個activity的屬性來做處理,即使這個activity設置了allowTaskReparenting;
? 如果activity的resultTo為空,並且滿足條件⑤,那麼將其及其以上未作處理的,滿足條件⑦的所有activity,一並進行TaskReparenting操作,並放置在mHistory棧底。它們在mHistory棧底順序如同在復用task中的順序;
? 根據①②③的條件來刪除復用task中相應的activity。
⑵ mHistory中,不屬於復用task的activity,並且它的resultTo不為空,那麼將根據它的前一個activity的處理來處理;
⑶ mHistory中,不屬於復用task,但是和當前啟動的activity有相同affinity,並且允許TaskReparenting操作,那麼將進行以下操作:
? 如果滿足上述的①②③④的條件,但是其中的task不是復用task,而是這個activity所處的task,那麼將輸出這個activity,而不是進行TaskReparenting操作。
為什麼非復用task中的activity,和當前啟動的activity有相同affinity,並且允許TaskReparenting操作,滿足了①②③④的條件之後要刪除呢,為什麼非復用task中的其他activity,不需要刪除呢?
正因為它和啟動的activity有相同的affinity,因此AMS認為這個activity是和啟動activity相關的,以後可能會重新調用,所以當其滿足刪除條件後,這時它將不允許TaskReparenting操作,並且不應該再允許它存在於其他的task中,此時應該刪除。
? 如果沒有滿足①②③④的條件,那麼將會對其進行TaskReparenting操作,重新將其移動到復用task或新啟動的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 = intentActivity.task;
                        reuseTask.performClearTaskLocked();//清空所有的Activity
                        reuseTask.setIntent(r.intent, r.info);
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0  // 啟動之後刪除其他Activity
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {                       
                        ActivityRecord top =
                                intentActivity.task.performClearTaskLocked(r, launchFlags);
                                // 這3種條件有一個共同點,就是啟動的activity啟動之後,在這個task中,這個activity之上不能有其他的activity
                        if (top != null) {
                            if (top.frontOfTask) {                    
                                top.task.setIntent(r.intent, r.info);
                            }
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                                    r, top.task);
                            /// M: AMS log enhancement @{
                            if(!ActivityManagerService.IS_USER_BUILD)
                               Slog.d(TAG, "ACT-AM_NEW_INTENT " + r + top.task);
                            /// @}
                            top.deliverNewIntentLocked(callingUid, r.intent);
                        } else {

                            addingToTask = true;

                            sourceRecord = intentActivity;

                        }
                    }
  //此時條件加上FLAG_ACTIVITY_NEW_TASK,且正要啟動的Activity為root Activity,並且是在棧頂顯示的
                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
                                && intentActivity.realActivity.equals(r.realActivity)) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                                    intentActivity.task);
                            if (intentActivity.frontOfTask) {
                                intentActivity.task.setIntent(r.intent, r.info);
                            }
                            /// M: AMS log enhancement @{
                            if (!ActivityManagerService.IS_USER_BUILD)
                                Slog.d(TAG, "ACT-AM_NEW_INTENT " + r + intentActivity.task);
                            /// @}
                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);
                            //判斷要啟動的Activity的包名是否為空,如果不為空的話,那麼得到mHistory最頂部的ActivityRecord
                            //,接著判斷當前頂部的Activity與要啟動的Activity是否相同,並且Activity的進程以及ApplicationThread不為空
                            //,接著如果判斷launchFlags為FLAG_ACTIVITY_SINGLE_TOP或者LaunchMode為SINGLE_TOP或者SINGLE_TASK的話,那麼就調用resumeTopActivityLocked
                                //,並且調用top.deliverNewIntentLocked回調Activity的onNewIntent。否則如果包名為空,那麼返回CLASS_NOT_FOUND結果。
                        } else if (!r.intent.filterEquals(intentActivity.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.
                            //我們要打開的app的初始界面不等於我們r.intent。即我們要新建r.intent的activity
                            addingToTask = true;
                            sourceRecord = intentActivity;

                            /// M: Add debug task message @{
                            if (DEBUG_TASKS) {
                                Slog.i(TAG, "since different intents, start new activity...");
                            }
                            /// @}
                        }
 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;
                        //addingToTask 如果為true表示正在添加至某個task
                        sourceRecord = intentActivity;
                        //在這種情況下只是把這個activity 移動到task頂部。並不重置這個task

                        /// M: Add debug task message @{
                        if (DEBUG_TASKS) {
                            Slog.i(TAG, "place the new activity on top of the current task...");
                        }
                        /// @}
                    } else if (!intentActivity.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.
                        intentActivity.task.setIntent(r.intent, r.info);
                    }

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:
   一般與FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET結合使用,如果設置該屬性,這個activity將在一個新的task中啟動或者或者被帶到一個已經存在的task的頂部,這時這個activity將會作為這個task的首個頁面加載。將會導致與這個應用具有相同親和力的task處於一個合適的狀態(移動activity到這個task或者從中移出),或者簡單的重置這個task到它的初始狀態
   FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:在當前的Task堆棧中設置一個還原點,當帶有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent請求啟動這個堆棧時(典型的例子是用戶從桌面再次啟動這個應用),還原點之上包括這個應用將會被清除。應用場景:在email程序中預覽圖片時,會啟動圖片觀覽的actvity,當用戶離開email處理其他事情,然後下次再次從home進入email時,我們呈現給用戶的應該是上次email的會話,而不是圖片觀覽,這樣才不會給用戶造成困惑。
例: 存在Activity A, Activity B, Activity C, Activity A啟動開僻Task堆棧, 命名為TaskA(TaskA堆棧狀態: A),
在Activity A中啟動Activity B(TaskA堆棧狀態: AB), 接著Activity B啟動Activity C(TaskA堆棧狀態: ABC),
啟動Activity C的Intent中設置FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET標題, 這樣TaskA中有一個還原點,
當有包含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent請求TaskA堆棧時(比如請求Activity A)
系統就會將還原點以上的Activity清除, TaskA堆棧中只剩下了AB.

   if (!addingToTask && reuseTask == null) {
                       //如果沒有正在添加至某個Task, 並且不用加入一個已清除所有Activity的Task
                //此時只需要顯示棧頂Activity即可 
                        if (doResume) {
                            targetStack.resumeTopActivityLocked(null, options);
                        } else {
                            ActivityOptions.abort(options);
                        }
                        /// M: Add debug task message @{
                        if (DEBUG_TASKS) {
                            Slog.i(TAG, "START_TASK_TO_FRONT, doResume = " + doResume);
                        }
                        /// @}
                        if (r.task == null)  Slog.v(TAG,
                            "startActivityUncheckedLocked: task left null",
                            new RuntimeException("here").fillInStackTrace());
                        return ActivityManager.START_TASK_TO_FRONT;
                    }
                    /// M: Fix ALPS01276300, reset mMovingToFront flag here @{
                    intentActivity.task.mMovingToFront = false;
                    /// @}

Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP
檢查Intent是否設置了Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,這個標志我有點困惑,從它的注釋可以看出它的含義是指如果設置了該flag,那麼mHistory中最top的activity在後續的處理中將不被視為top,而將前一個activity視為top,如A–>B–>C,將B視為top。
這個top activity的作用很大,涉及到後面對task的處理。但是目前來看這個flag並沒有起到該有的作用,代碼中判斷如果設置了該標志,那麼AMS將會視當前正在啟動的activity為top,然後去mHistory中去查找它的前一個activity為後續task處理的top activity(topRunningNonDelayedActivityLocked()中實現),但是現在的問題是此時此刻,正在啟動的activity並不存在於mHistory中,因為我們在前一個函數中剛剛創建了這個ActivityRecord。如下面代碼所示:
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
因此,感覺這個flag的意義不是太大。

if (r.packageName != null) {
            ActivityStack topStack = getFocusedStack();
            ActivityRecord top = topStack.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) {//檢測是否可復用Activity,top為Launcher,r為Setting,不滿足
                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
                                    top.task);
                            topStack.mLastPausedActivity = null;
                            if (doResume) {
                                resumeTopActivitiesLocked();
                            }
                            ActivityOptions.abort(options);
                            if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {

                                if (r.task == null)  Slog.v(TAG,
                                    "startActivityUncheckedLocked: task left null",
                                    new RuntimeException("here").fillInStackTrace());
                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                            }
                            top.deliverNewIntentLocked(callingUid, r.intent);
                           //    當設置Intent.FLAG_ACTIVITY_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK這幾種情況下,如果top activity與啟動的activity為同一個activity,那麼將復用top activity,並直接resume top activity
                            if (r.task == null)  Slog.v(TAG,
                                "startActivityUncheckedLocked: task left null",
                                new RuntimeException("here").fillInStackTrace());
                            return ActivityManager.START_DELIVERED_TO_TOP;
                        }
                    }
                }
            }
else {
if (r.resultTo != null) {
r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
r.requestCode, Activity.RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
if (r.task == null) Slog.v(TAG,
“startActivityUncheckedLocked: task left null”,
new RuntimeException(“here”).fillInStackTrace());
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) {
            targetStack = adjustStackFocus(r);//adjustStackFocus()獲取目標stack。
            moveHomeStack(targetStack.isHomeStack());
            if (reuseTask == null) {
                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                        newTaskInfo != null ? newTaskInfo : r.info,
                        newTaskIntent != null ? newTaskIntent : intent,
                        true), null, true);
                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                        r.task);
            } else {//如果reuse不為空,此時啟動 c 會把 A B 清空
                r.setTask(reuseTask, reuseTask, true);
            }
            newTask = true;
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved