Android Activity生命周期和啟動(dòng)模式你不知道的那些事

此文是根據(jù)官方文檔、圖書資料及demo測(cè)試得出的結(jié)論,包括Activity多個(gè)頁(yè)面間跳轉(zhuǎn)的生命周期,各個(gè)啟動(dòng)模式的不同,flag的常見用法及對(duì)activity任務(wù)棧的影響。

Activity生命周期需要注意的地方

  • 當(dāng)Activity長(zhǎng)時(shí)間在后臺(tái)運(yùn)行時(shí),可能會(huì)被殺死,再次啟動(dòng)時(shí)Activity會(huì)被重建,此情況和橫豎屏切換場(chǎng)景類似,開發(fā)者應(yīng)該在開發(fā)環(huán)境下打開橫豎屏切換測(cè)試,防止異常發(fā)生;
  • 如果新的Activity是透明主題,則當(dāng)前Activity不會(huì)執(zhí)行onStop;
  • onSaveInstanceState在onStop之前執(zhí)行,onRestoreInstanceState在onStart之后執(zhí)行;
  • 為防止Activity橫豎屏切換時(shí)Activity重啟,可添加 android:configChanges="orientation|screenSize"
  • onStart和onStop,判斷Activity是否可見,onResume和onPause,判斷Activity是否在前臺(tái);
  • A啟動(dòng)B,A、B生命周期執(zhí)行順序:A會(huì)先進(jìn)入后臺(tái),B創(chuàng)建進(jìn)入前臺(tái),A不可見;
A(onPause) --> B(onCreate) --> B(onStart) --> B(onResume) --> A(onSaveInstanceState) ->A(onStop) 

Activity啟動(dòng)模式

Standard:標(biāo)準(zhǔn)模式

  • 每次都會(huì)新創(chuàng)建Activity,并添加到對(duì)應(yīng)的任務(wù)棧中;

SingleTop:棧頂復(fù)用

  • 如果要啟動(dòng)的Activity已經(jīng)在棧頂,該Activity不會(huì)被創(chuàng)建;

    * A --> B(SingleTop)
    * 再次啟動(dòng)B后生命周期:
    onPause --> onNewIntent --> onResume
    
  • 如果要啟動(dòng)的Activity不在棧頂,跟標(biāo)準(zhǔn)模式完全一致;

    * A --> B(SingleTop) --> C
    * 再次啟動(dòng)B后棧:
    A --> B(SingleTop) --> C --> B(SingleTop)
    

SingleTask:棧內(nèi)復(fù)用模式

  • 特別注意,配置此模式的Activity并不會(huì)位于一個(gè)新的任務(wù)棧中,只是如果要啟動(dòng)的Activity已經(jīng)在棧中,會(huì)clearTop,讓自己置為棧頂;

    * A --> B(SingleTask) --> C
    TaskRecord{ed93b47 #259 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=4}
        Run #3: ActivityRecord{c1f4817 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t259}
        Run #2: ActivityRecord{59e1a72 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t259}
        Run #1: ActivityRecord{d7ae33c u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t259}
        
    * 再次啟動(dòng)B后任務(wù)棧:
    A --> B(SingleTask)
    此時(shí)C會(huì)被銷毀
    此時(shí)B的生命周期:onPause --> onNewIntent --> onResume
        
    TaskRecord{ed93b47 #259 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #2: ActivityRecord{59e1a72 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t259}
        Run #1: ActivityRecord{d7ae33c u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t259}
    

SingleInstance:?jiǎn)螌?shí)例模式

  • 此模式的Activity只能位于一個(gè)獨(dú)立任務(wù)棧中;

    * A --> B(SingleInstance) --> C
    此時(shí),A、C位于同一個(gè)任務(wù)棧,B位于獨(dú)立的任務(wù)棧;
        
    TaskRecord{c37f244 #253 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #3: ActivityRecord{8d06468 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t253}
    TaskRecord{10b2e56 #257 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=1}
        Run #2: ActivityRecord{eeb0317 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t257}
    TaskRecord{c37f244 #253 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #1: ActivityRecord{e25c532 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t253}
        
    * 再次啟動(dòng)B后棧:
    A --> C --> B(SingleInstance)
    此時(shí),B調(diào)整為前臺(tái)任務(wù)棧,A、C的任務(wù)棧調(diào)整為后臺(tái)任務(wù)棧;
    此時(shí),B的生命周期:onPause --> onNewIntent --> onResume
    
    TaskRecord{10b2e56 #257 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=1}
        Run #3: ActivityRecord{eeb0317 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t257}
    TaskRecord{c37f244 #253 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #2: ActivityRecord{8d06468 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t253}
        Run #1: ActivityRecord{e25c532 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t253}
    

怎么確定Activity位于哪個(gè)任務(wù)棧

  • 除SingleInstance模式的activity外,其它所有模式的activity都會(huì)被添加到默認(rèn)的任務(wù)棧中,默認(rèn)任務(wù)棧taskAffinity為包名;

  • 可以通過指定taskAffinity讓activity運(yùn)行在特定的任務(wù)棧中,必須配合FLAG_ACTIVITY_NEW_TASK才會(huì)生效;

  • 除SingleInstance模式的activity外,啟動(dòng)普通的activity都被添加到啟動(dòng)此activity所用的activity相同的任務(wù)棧中,除非同時(shí)指定taskAffinity和FLAG_ACTIVITY_NEW_TASK,會(huì)運(yùn)行在與taskAffinity同名的任務(wù)棧中;

    * A --> B(taskAffinity=test.gcoder.io.newtask flag=FLAG_ACTIVITY_NEW_TASK)
    TaskRecord{99b9ba5 #269 A=test.gcoder.io.newtask, isShadow:false U=0 sz=1}
        Run #2: ActivityRecord{5ba0ca2 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t269}
    TaskRecord{ab040b2 #267 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=2}
        Run #1: ActivityRecord{1ddfc0 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t267}
        
    * A --> B(taskAffinity=test.gcoder.io.newtask flag=FLAG_ACTIVITY_NEW_TASK)--> C
    TaskRecord{99b9ba5 #269 A=test.gcoder.io.newtask, isShadow:false U=0 sz=2}
        Run #3: ActivityRecord{199ec49 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t269}
        Run #2: ActivityRecord{5ba0ca2 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t269}
    TaskRecord{ab040b2 #267 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=2}
        Run #1: ActivityRecord{1ddfc0 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t267}
    

Context對(duì)Activity任務(wù)棧的影響

  • 經(jīng)過對(duì)比,使用Activity Context啟動(dòng)與使用Application Context啟動(dòng)Activity無任何區(qū)別,都是在一個(gè)任務(wù)棧中;

  • 使用Activity Context啟動(dòng)

    * A --> B(FLAG_ACTIVITY_NEW_TASK)
    TaskRecord{6a79d7e #261 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #2: ActivityRecord{8754172 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t261}
        Run #1: ActivityRecord{43b510 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t261}
            
    * A --> B(FLAG_ACTIVITY_NEW_TASK)-->C
    TaskRecord{6a79d7e #261 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=4}
        Run #3: ActivityRecord{4095453 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t261}
        Run #2: ActivityRecord{8754172 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t261}
        Run #1: ActivityRecord{43b510 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t261}   
    
  • 使用Application Context啟動(dòng)

    * A --> B(FLAG_ACTIVITY_NEW_TASK)
    TaskRecord{eb6f24d #262 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #2: ActivityRecord{215a79a u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t262}
        Run #1: ActivityRecord{7e22051 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t262}
          
    * A --> B(FLAG_ACTIVITY_NEW_TASK)--> C      
    TaskRecord{eb6f24d #262 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=4}
        Run #3: ActivityRecord{dac68e6 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t262}
        Run #2: ActivityRecord{215a79a u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t262}
        Run #1: ActivityRecord{7e22051 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t262}
        
    * 再次啟動(dòng)B后:A --> B(FLAG_ACTIVITY_NEW_TASK) --> C --> B(FLAG_ACTIVITY_NEW_TASK)      
    TaskRecord{eb6f24d #262 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=5}
        Run #4: ActivityRecord{2ec8ea1 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t262}
        Run #3: ActivityRecord{c30b233 u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t262}
        Run #2: ActivityRecord{e88653e u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t262}
        Run #1: ActivityRecord{177c4a8 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t262}
    

Flag對(duì)Activity任務(wù)棧的影響

FLAG_ACTIVITY_NEW_TASK

  • 只添加此Flag的Activity不會(huì)被添加新的任務(wù)棧中,此時(shí)跟SingleTask無任何關(guān)系,也不具備SingleTask同一個(gè)任務(wù)棧中唯一的特性及clearTop的特性;
  • 此Flag可被用于非Activity類型的Context啟動(dòng)新Activity;
  • 此Flag與其它Flag混合使用會(huì)有不同的效果;

FLAG_ACTIVITY_MULTIPLE_TASK

  • 此Flag一般不單獨(dú)使用,需要配合FLAG_ACTIVITY_NEW_TASK使用;

FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_NEW_TASK

  • 單獨(dú)使用時(shí),會(huì)檢索已經(jīng)存在的任務(wù)棧,如果啟動(dòng)的activity對(duì)應(yīng)的任務(wù)棧存在就不會(huì)創(chuàng)建,不存在才會(huì)創(chuàng)建新的任務(wù)棧;

  • 同時(shí)使用時(shí),會(huì)強(qiáng)制創(chuàng)建新的任務(wù)棧,并將啟動(dòng)的activity放在新的任務(wù)棧中, 后續(xù)使用此activity啟動(dòng)的標(biāo)準(zhǔn)模式的activity會(huì)運(yùn)行在此棧中,而不是默認(rèn)棧中;

    * A --> B(FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_ACTIVITY_NEW_TASK)
    TaskRecord{4144b1a0 #6 A test.gcoder.io.testactivity U 0}
        Run #3: ActivityRecord{413fd7a8 test.gcoder.io.testactivity/.BActivity}
    TaskRecord{41548560 #5 A test.gcoder.io.testactivity U 0}
        Run #2: ActivityRecord{41562330 test.gcoder.io.testactivity/.AActivity}
            
    * A --> B(FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_ACTIVITY_NEW_TASK) --> C
    TaskRecord{4144b1a0 #6 A test.gcoder.io.testactivity U 0}
        Run #4: ActivityRecord{41604278 test.gcoder.io.testactivity/.CActivity}
        Run #3: ActivityRecord{413fd7a8 test.gcoder.io.testactivity/.BActivity}
    TaskRecord{41548560 #5 A test.gcoder.io.testactivity U 0}
        Run #2: ActivityRecord{41562330 test.gcoder.io.testactivity/.AActivity}
       
    * A --> B(FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_ACTIVITY_NEW_TASK) --> C --> B(FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_ACTIVITY_NEW_TASK)
    TaskRecord{41434a90 #7 A test.gcoder.io.testactivity U 0}
        Run #5: ActivityRecord{413a6710 test.gcoder.io.testactivity/.BActivity}
    TaskRecord{4144b1a0 #6 A test.gcoder.io.testactivity U 0}
        Run #4: ActivityRecord{41604278 test.gcoder.io.testactivity/.CActivity}
        Run #3: ActivityRecord{413fd7a8 test.gcoder.io.testactivity/.BActivity}
    TaskRecord{41548560 #5 A test.gcoder.io.testactivity U 0}
        Run #2: ActivityRecord{41562330 test.gcoder.io.testactivity/.AActivity} 
    

FLAG_ACTIVITY_SINGLE_TOP

  • 同SingleTop

FLAG_ACTIVITY_CLEAR_TOP

  • 此Flag單獨(dú)使用時(shí),如果啟動(dòng)的Activity存在對(duì)應(yīng)的任務(wù)棧中,只是會(huì)清除任務(wù)棧中要啟動(dòng)的Activity之上所有的Activity,要啟動(dòng)的Activity會(huì)先銷毀后重新創(chuàng)建;

  • 此Flag單獨(dú)使用時(shí),如果啟動(dòng)的Activity不存在對(duì)應(yīng)的任務(wù)棧中,則創(chuàng)建并添加到對(duì)應(yīng)的任務(wù)棧中;

    * A --> B(FLAG_ACTIVITY_CLEAR_TOP) --> C
    TaskRecord{166703a #289 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=4}
        Run #3: ActivityRecord{374b0ff u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t289}
        Run #2: ActivityRecord{15086 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t289}
        Run #1: ActivityRecord{da843b0 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t289}
            
    * 再次啟動(dòng)B(FLAG_ACTIVITY_CLEAR_TOP)
    * 生命周期:C會(huì)銷毀,B會(huì)先銷毀后創(chuàng)建
    C(onPause)
    B(onDestroy)-->B(onCreate)-->B(onStart)-->B(onResume)
    C(onStop)-->C(onDestroy)
        
    TaskRecord{166703a #289 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=3}
        Run #2: ActivityRecord{6420128 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t289}
        Run #1: ActivityRecord{da843b0 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t289}
    

FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK

  • 如果要啟動(dòng)的Activity在對(duì)應(yīng)的任務(wù)棧中,則會(huì)銷毀任務(wù)棧頂部的所有 Activity,并通過 onNewIntent() 將此 Intent 傳遞給 Activity 已恢復(fù)的實(shí)例(現(xiàn)在位于頂部),而不是啟動(dòng)該 Activity 的新實(shí)例;

  • 如果啟動(dòng)的Activity沒有在對(duì)應(yīng)的任務(wù)棧中,則創(chuàng)建新的任務(wù)棧,創(chuàng)建Activity并添加到新的任務(wù)棧中;

    * A --> B(FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_CLEAR_TOP)
    TaskRecord{413377c #286 A=test.gcoder.io.newtask, isShadow:false U=0 sz=1}
        Run #2: ActivityRecord{a58be9a u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t286}
    TaskRecord{cfe9805 #285 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=2}
        Run #1: ActivityRecord{b5a1c24 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t285}
        
    * A --> B(FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_CLEAR_TOP)--> C
    TaskRecord{413377c #286 A=test.gcoder.io.newtask, isShadow:false U=0 sz=2}
        Run #3: ActivityRecord{9f7c8df u0 test.gcoder.io.testactivity/.CActivity, isShadow:false t286}
        Run #2: ActivityRecord{a58be9a u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t286}
    TaskRecord{cfe9805 #285 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=2}
        Run #1: ActivityRecord{b5a1c24 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t285}
        
    * 再次啟動(dòng)B(FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_CLEAR_TOP)
    * 生命周期:C會(huì)銷毀,B會(huì)先銷毀后創(chuàng)建
    C(onPause)
    B(onDestroy)-->B(onCreate)-->B(onStart)-->B(onResume)
    C(onStop)-->C(onDestroy)
        
    TaskRecord{413377c #286 A=test.gcoder.io.newtask, isShadow:false U=0 sz=1}
        Run #2: ActivityRecord{ff16c57 u0 test.gcoder.io.testactivity/.BActivity, isShadow:false t286}
    TaskRecord{cfe9805 #285 A=test.gcoder.io.testactivity, isShadow:false U=0 sz=2}
        Run #1: ActivityRecord{b5a1c24 u0 test.gcoder.io.testactivity/.AActivity, isShadow:false t285} 
    

注:如果指定 Activity 的啟動(dòng)模式為 "standard",則該 Activity 也會(huì)從堆棧中移除,并在其位置啟動(dòng)一個(gè)新實(shí)例,以便處理傳入的 Intent。 這是因?yàn)楫?dāng)啟動(dòng)模式為 "standard" 時(shí),將始終為新 Intent 創(chuàng)建新實(shí)例。

參考資料:

本文作者:gcoder.io
本文鏈接:http://gcoder-io.github.io/2016/10/05/android-activity-lifecycle-launchmode/
版權(quán)聲明: 本博客所有文章均為原創(chuàng),轉(zhuǎn)載請(qǐng)注明作者及出處

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

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

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