Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中Activity生命周期和啟動模式詳解

Android中Activity生命周期和啟動模式詳解

編輯:關於Android編程

Activity生命周期經典圖解:


按鍵對生命周期的影響:

BACK鍵:

  當我們按BACK鍵時,我們這個應用程序將結束,這時候我們將先後調用onPause()->onStop()->onDestory()三個方法。

再次啟動App時,會執行onCreate()->onStart()->onResume()

HOME鍵:

  當我們打開應用程序時,比如浏覽器,我正在浏覽NBA新聞,看到一半時,我突然想聽歌,這時候我們會選擇按HOME鍵,然後去打開音樂應用程序,而當我們按HOME的時候,Activity先後執行了onPause()->onStop()這兩個方法,這時候應用程序並沒有銷毀。

而當我們從桌面再次啟動應用程序時,則先後分別執行了onRestart()->onStart()->onResume()三個方法。

一般Activity切換正常生命周期(這裡的一般是指啟動模式為standard,切換activity時沒有加flag標志):

ActivityA啟動ActivityB:

ActivityA 的生命周期onPause()->onStop(),

ActivityB的生命周期onCreate()->onStart()->onResume()。

ActivityB執行finish返回ActivityA:

ActivityB的生命周期onPause()->onStop()->onDestory()

ActivityA的生命周期了onRestart()->onStart()->onResume()

注意:當ActivityB定義為Dialog樣式時,ActivityA的生命周期是不一樣的,

我們給ActivityB加上theme

<style name="MyDialogStyle"> 
   <item name="android:windowBackground">@android:color/transparent</item> 
   <item name="android:windowFrame">@null</item> 
   <item name="android:windowNoTitle">true</item> 
   <item name="android:windowIsFloating">true</item> 
   <item name="android:windowIsTranslucent">true</item> 
   <item name="android:windowContentOverlay">@null</item> 
   <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> 
   <item name="android:backgroundDimEnabled">true</item> 
 </style> 

這個時候,ActivityA啟動ActivityB,B沒有完全遮擋A,ActivityB的生命周期跟剛才一樣,但是ActivityA並沒有執行onStop()

還有一點需要特別注意,Activity中直接彈dialog,Acitivity的生命周期是不會變化的。網上有些說法是會執行onPause(),其實並沒有執行!

另外還有幾個跟生命周期相關的方法

@Override 
 protected void onNewIntent(Intent intent) { 
   super.onNewIntent(intent); 
 } 
 @Override 
 protected void onSaveInstanceState(Bundle outState) { 
   super.onSaveInstanceState(outState); 
 } 
 @Override 
 protected void onRestoreInstanceState(Bundle savedInstanceState) { 
   super.onRestoreInstanceState(savedInstanceState); 
 } 
 @Override 
 public void onConfigurationChanged(Configuration newConfig) { 
   super.onConfigurationChanged(newConfig); 
 } 

當應用運行起來後就會開啟一條線程,線程中會運行一個任務棧,當Activity實例創建後就會放入任務棧中。Activity啟動模式的設置在AndroidManifest.xml文件中,通過配置Activity的屬性android:launchMode=""設置。

1. Standard模式(默認)

我們平時直接創建的Activity都是這種模式的Activity,這種模式的Activity的特點是:只要你創建了Activity實例,一旦激活該Activity,則會向任務棧中加入新創建的實例,退出Activity則會在任務棧中銷毀該實例。
standard模式是所啟動的Activity都是在同一個task容器棧下,不會重新創建新的task容器棧。先壓入棧的Activity實例按順序入棧底,後入棧在棧頂,處於棧的頂部Activity實例處於活動狀態,其他處於非活動狀態。按物理返回鍵,退出當前所處活動狀態Activity窗口,這樣就會從task容器棧中彈出,顯示在手機主屏幕上,從而,有非活動狀態轉換成活動的狀態。其次,standard容器棧可能會存在著相同的Activity實例,只有沒調用一次startActivity方法,就會創建目標Activity實例對象壓入task容器棧。
如果Activity啟動順序為A->B->B->A->D,棧中的Acitivy為ABBAD(最先創建的A位於棧底,最後創建的D位於棧頂)

2. SingleTop模式

這種模式會考慮當前要激活的Activity實例在任務棧中是否正處於棧頂,如果處於棧頂則無需重新創建新的實例,會重用已存在的實例,否則會在任務棧中創建新的實例。
SingleTop有個不錯的用法是防止多次點擊創建多個Activity,無論start幾次,SingleTop模式能保證棧頂只有一個實例。 如果Activity啟動順序為A->B->B->A->D,棧中的Acitivy為ABAD(當B位於棧頂時,再次啟動B的時候,B不會重新創建)

3. SingleTask模式

如果任務棧中存在該模式的Activity實例,則把棧中該實例以上的Activity實例全部移除,調用該實例的newInstance()方法重用該Activity,使該實例處於棧頂位置,否則就重新創建一個新的Activity實例。
singletask模式,特別需要注意了。啟動的目標Activity實例如果已經存在task容器棧中,不管當前實例處於棧的任何位置,是棧頂也好,棧底也好,還是處於棧中間,只要目標Activity實例處於task容器棧中,都可以重用該Activity實例對象,然後,把處於該Activity實例對象上面全部Activity實例清除掉,並且,task容器棧中永遠只有唯一實例對象,不會存在兩個相同的實例對象。所以,如果你想你的應用不管怎麼啟動目標Activity,都只有唯一一個實例對象,就使用這種啟動模式。 如果Activity啟動順序為A->B->B->A->D,棧中的Acitivy為AD(當A再次被啟動時,A會被移到棧頂,位於A上面的Acitivity全部會出棧)

4. SingleInstance模式

當該模式Activity實例在任務棧中創建後,只要該實例還在任務棧中,即只要激活的是該類型的Activity,都會通過調用實例的newInstance()方法重用該Activity,此時使用的都是同一個Activity實例,它都會處於任務棧的棧頂。此模式一般用於加載較慢的,比較耗性能且不需要每次都重新創建的Activity。

singleInstance啟動模式,簡單說就是可以共享某個Activity。比如,應用1的任務容器棧中創建了MainActivity實例,應用2也要激活MainActivity,則不需要創建MainActivity實例,直接可以公用MainActivity實例。 尤其值得注意:應用1啟動MainActivity,按home鍵;打開應用2啟動應用1的MainActivity實例。在按home鍵,打開應用1,這時候應用1的界面是應該是處於MainActivity界面實例。 SingleInstance的一個任務棧中只有一個Activity,並保證不再有其他Activity實例進入。

特別需要注意的生命周期onNewIntent

當一個Activity被start,而不需要重新創建時,就會執行onNewIntent生命周期。如果一個Activity的啟動模式是SingleTask,我們可以在onNewIntent中執行一些刷新操作等。

我們一般會把MainAcitivy設置為SingleTask,除了保證MainActivity的唯一,還可以利用singleTask的特性做一些清理工作。自動管理棧,銷毀無用的Acitivity.

Intent Flags

 Flags: 表示Intent的標志位,常用於Activity的場景中,它和Activity的啟動模式有著密切的聯系。

下面列舉的是和本文主題相關的Flags屬性:

Intent.FLAG_ACTIVITY_NEW_TASK (默認)

默認的跳轉類型,它會重新創建一個新的Activity,不過與這種情況,比如說Task1中有A,B,C三個Activity,此時在C中啟動D的話,如果在AndroidManifest.xml文件中給D添加了Affinity的值和Task中的不一樣的話,則會在新標記的Affinity所存在的Task中壓入這個Activity。如果是默認的或者指定的Affinity和Task一樣的話,就和標准模式一樣了啟動一個新的Activity.

FLAG_ACTIVITY_SINGLE_TOP這個FLAG就相當於啟動模式中的singletop,例如:原來棧中結構是A B C D,在D中啟動D,棧中的情況還是A,B,C,D。

FLAG_ACTIVITY_CLEAR_TOP這個FLAG就相當於啟動模式中的SingleTask,這種FLAG啟動的Activity會把要啟動的Activity之上的Activity全部彈出棧空間。例如:原來棧中的結構是A B C D ,從D中跳轉到B,棧中的結構就變為了A B了。

FLAG_ACTIVITY_BROUGHT_TO_FRONT

這個網上很多人是這樣寫的。如果activity在task存在,拿到最頂端,不會啟動新的Activity。這個有可能會誤導大家! 他這個FLAG其實是這個意思!比如說我現在有A,在A中啟動B,此時在A中Intent中加上這個標記。此時B就是以FLAG_ACTIVITY_BROUGHT_TO_FRONT方式啟動,此時在B中再啟動C,D(正常啟動C,D),如果這個時候在D中再啟動B,這個時候最後的棧的情況是 A,C,D,B。如果在A,B,C,D正常啟動的話,不管B有沒有用FLAG_ACTIVITY_BROUGHT_TO_FRONT啟動,此時在D中啟動B的話,還是會變成A,C,D,B的。

FLAG_ACTIVITY_NO_USER_ACTION

onUserLeaveHint()作為activity周期的一部分,它在activity因為用戶要跳轉到別的activity而要退到background時使用。比如,在用戶按下Home鍵,它將被調用。比如有電話進來(不屬於用戶的選擇),它就不會被調用。
那麼系統如何區分讓當前activity退到background時使用是用戶的選擇?

它是根據促使當前activity退到background的那個新啟動的Activity的Intent裡是否有FLAG_ACTIVITY_NO_USER_ACTION來確定的。
注意:調用finish()使該activity銷毀時不會調用該函數

FLAG_ACTIVITY_NO_HISTORY

意思就是說用這個FLAG啟動的Activity,一旦退出,它不會存在於棧中,比如原來是A,B,C這個時候再C中以這個FLAG啟動D的,D再啟動E,這個時候棧中情況為A,B,C,E。

Activity相關屬性taskAffinity

Activity 中的 android:taskAffinity 這個屬性介紹:
Activity為Task擁有的一個affinity。擁有相同的affinity的Activity理論上屬於相同的Task(在用戶的角度是相同的“應用程序”)。Task的affinity是由它的根Activity決定的。 

affinity決定兩件事情——Activity重新宿主的Task(參考allowTaskReparenting特性)和使用FLAG_ACTIVITY_NEW_TASK標志啟動的Activity宿主的Task。

默認情況,一個應用程序中的所有Activity都擁有相同的affinity。捏可以設定這個特性來重組它們,甚至可以把不同應用程序中定義的Activity放置到相同的Task中。為了明確Activity不宿主特定的Task,設定該特性為空的字符串。

如果這個特性沒有設置,Activity將從應用程序的設定那裡繼承下來(參考<application>元素的taskAffinity特性)。應用程序默認的affinity的名字是<manifest>元素中設定的package名。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved