Android生命週期與啓動模式

Android 生命週期與啓動模式

1.1 Android 生命週期

參考資料:
https://www.gitbook.com/book/tom510230/android_ka_fa_yi_shu_tan_suo/details
官方文檔

生命週期分爲兩部分:一部分是典型(正常)的生命週期,用戶參與下所經歷的生命週期,比如手動啓動Activity和銷燬Activity。另一部分是異常情況下的生命週期,比如Activity被系統回收或設備Configuration發生變化導致的Activity被銷燬重建。

1.1.1 典型情況的生命週期

說明:

  1. 第一次啓動某一個Activity回調:onCreate->onStart->onResume;
  2. back鍵退出當前Activity回調:onPause->onStop->onDestory;
  3. home鍵或打開新的Activity回調:onPause->onStop,如果Activity採用透明主題,則不會調用onStop。
  4. 再次回到原Activity回調:onRestart->onStart->onResume;
  5. 打開新的Activity回調:A:onPause-> B:onCreate-> B:onStart-> B:onResume-> A:onStop

    說明:舊的Activity的onPause先調用,然後新的Activity才啓動,所以在onPause中要避免做重量級操作,在官方文檔中有體現:

1.1.2 異常情況下的生命週期分析

1. 資源相關的系統配置發生改變導致Activity被殺死

旋轉屏幕等會導致系統配置發生變化,默認情況下,Activity會被銷燬並且重新創建,也可以人爲的阻止系統重建。
在默認情況下,不對Activity做任何處理,那麼系統變化後,會被銷燬和重建:生命週期如下:

只有在異常情況下(在home或啓動其他Activity的時候也會單獨調用onSaveInstanceState),Activity會在onStop之前調用onSaveInstanceState,與onPause無特定順序,當Activity被重新創建的時候,系統會在onStart之後調用onRestoreInstanceState,並把Activity銷燬時保存的bundle數據作爲參數傳給onRestoreInstanceState。

關於數據保存和恢復,Activity調用onSaveInstanceState保存數據--> Activity委託Window保存數據--> Window委託頂級容器(ViewGroup,可能是DecorView)保存數據--> ViewGroup通知子元素保存數據。這是一種典型的委託模式,典型的委託模式還有View繪製過程事件分發等。

上面被銷燬並進行了重建,那什麼情況下不會被重建呢?
如果不想被重建,那麼可以給Activity指定configChange屬性:比如android:configChanges=”orientation”屏幕旋轉的時候不會進行重建,也不會調用onSaveInstanceState和onRestoreInstanceState,而是調用onConfigurationChanged方法。
配置常見的有三種:locale、orientation、keyboardHidden

2. 資源內存不足導致優先級低的Activity被殺死

Activity優先級從高到低:

  1. 前臺Activity--正在與用戶進行交互的Activity優先級最高。
  2. 可見但非前臺Activity--彈出對話框等導致的Activity可見但無法交互。
  3. 後臺Activity--已經被暫停的Activity,比如執行了onStop(切在後臺),優先級最低。

1.2 Activity的啓動模式

1.2.1 Activity的LuncherMode

  1. standard:標準、默認模式,不管在棧中是否存在,都會創建Activity實例在啓動它的Activity所在的棧中。需要注意:創建的實例默認會在啓動它的Activity所在的棧中,那麼,非Activity的Context(ApplicationContext)並不存在所謂的任務棧,所以會報錯,解決方法就是爲待啓動Activity指定FLAG_ACTIVITY_NEW_TASK標誌位,啓動的時候爲其創建一個任務棧,而添加了FLAG_ACTIVITY_NEW_TASK的Flag,實際就變成了以singleTask模式啓動。後面會說到Flag。
  2. singleTop:棧頂複用模式,如果新的Activity在棧頂,則不會創建,同時回調onNewIntent,onCreate、onStart不會被回調,因爲Activity沒有創建。
  3. singleTask: 棧內複用模式,單實例模式,只要Activity在一個棧中存在,那多次啓動都不會創建Activity,會回調onNewIntent,同時要啓動的Activity之上的Activity全部被清除出棧,如果不存在,則重新創建一個任務棧,然後創建Activity放入棧中。
  4. singleInstance:單實例模式,加強版singleTask,此模式的Activity單獨位於一個任務棧中。

TaskAffinity的運用

1.2.2 Activity的Flags

標記位一般與啓動模式相關,會影響Activity的運行狀態。
常見的幾種Flags:

  1. FLAG_ACTIVITY_NEW_TASK:其效果等同於爲Activity指定“singleTask”的啓動模式。
  2. FLAG_AVCTIVITY_SINGLE_TOP:其效果等同於爲Activity設置“singleTop”的啓動模式。
  3. FLAG_ACTIVITY_CLEAR_TOP:清除同一任務棧中位於它上面的Activity,一般與FLAG_ACTIVITY_NEW_TASK配合使用,被啓動的Activity如果已存在,那麼就會調用onNewIntent方法,如果被啓動的Activity使用standard模式,那它連同他之上的都要出棧,會重新創建實例,放入棧頂。
  4. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此標記位的Activity不會出現在歷史Activity列表中(Android 多任務管理器查看的時候不會顯示),等同於xml中指定Activity屬性爲:android:excludeFromRecents=”true”;

官方文檔:Intent-Flags

1.3 IntentFilter的匹配規則

啓動Activity分爲兩種:顯式調用和隱式調用。顯式調用明確指定被啓動對象的組件信息,包括類名和包名。隱式調用根據過濾信息進行匹配,同時使用隱式和顯式時,以顯式爲主。匹配的信息:action、category、data,可以有多組intent-filter,只有同時匹配一組才能啓動目標Activity。
1. action: action的字符串完全一致纔算匹配成功,區分大小寫,一組intent-filter可以有多個action,匹配一個就算成功。
2. category: category是一個字符串,系統預定義了一些category,Intent可以沒有category,如果有,不管幾個,都必須和intent-filter過濾規則中的category匹配。不設置可以匹配是因爲在startActivity或startActivityForResult的時候會默認添加“android.intent.category.DEFAULT”這個category。
3. data: data的匹配規則與action類似,data由兩部分組成:mimeType和URI。mimeType指媒體類型,比如image/jepg、audio/mpeg4-generic和video/*等,可以表示圖片文本視頻等不同媒體類型,而URI包含的數據比較多,大致結構:

    <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

結合實例:

    content://com.example.project:200/folder/subfolder/etc
    http://www.baidu.com:80/search/info

Scheme: URI的模式,比如http、file,沒有指定,其他參數無效,URI無效。
Host: URI的主機,比如www.baidu.com,未指定,其他參數無效,URI無效。
Port: URI中的端口號,比如80,指定了Scheme和Host,Port纔有效。
Path、pathPattern、pathPrefix: 表示路徑信息,path、pathPattern表示完整路徑,可以包含通配符*,表示0或多個任意字符,pathPrefix表示路徑的前綴信息。

例子:

    <data android:scheme="string"
        android:host="string"
        android:port="string"
        android:path="string"
        android:pathPattern="string"
        android:pathPrefix="string"
        android:mimeType="string"/>

隱式意圖注意內容:

通過隱式意圖啓動Activity的時候,可以做一下判斷,看是否有 Activity匹配到隱式意圖,不做判斷,匹配不到可能會出現ActivityNotFoundException異常,判斷的方式:PackageManager的resolveActivity或着Intent的resolveActivity,另外PackageManager提供了queryIntentActivities方法,返回值是所有匹配的Activity信息。

    public abstract List<ResolveInfo> queryIntentActivities(Intent intent,@ResolveInfoFlags int flags);
    public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);

需要注意的是,第二個參數使用MATCH_DEFAULT_ONLY 僅僅匹配在intent-filter中聲明瞭android.intent.category.DEFAULT的category的Activity,意義在於,只要不返回null,那麼startActivity一定會成功。

還有一類action和category比較重要:

    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />

二者共同作用,表明這是程序入口的Activity並且出現在系統應用列表中,二者缺一不可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章