Activity作為四大組件之一,也可以說是四大組件中最重要的一個組件,它負責App的視圖,還負責用戶交互,而且有時候還經常其他組件綁定使用,可以說非常的重要。
雖然說我們天天都在使用Activity,但是你真的對Activity的生命機制爛熟於心,完全了解了嗎?的確,Activity的生命周期方法只有七個(自己數-。+),但是其實那只是最平常的情況,或者說是默認的情況。也就是說在其他情況下,Activity的生命周期可能不會是按照我們以前所知道的流程,這就要說到我們今天的重點了——Activity的啟動模式:我們的Activity會根據自身不同的啟動模式,自身的生命周期方法會進行不同的調用。
一、在將啟動模式之前必須了解的一些知識:
在正式的介紹Activity的啟動模式之前,我們首先要了解一些旁邊的知識,這些知識如果說模糊不清,那么在討論啟動模式的時候會一頭霧水(筆者親身感悟)。
- 一個應用程序通常會有多個Activity,這些Activity都有一個對應的action(如MainActivity的action),我們可以通過action來啟動對應Activity(隱式啟動)。
<action android:name="android.intent.action.MAIN" />
-
一個應用程序可以說由一系列組件組成,這些組件以進程為載體,相互協作實現App功能。
-
任務棧(Task Stack)或者叫退回棧(Back Stack)介紹:
3.1.任務棧用來存放用戶開啟的Activity。
3.2.在應用程序創建之初,系統會默認分配給其一個任務棧(默認一個),並存儲根Activity。
3.3.同一個Task Stack,只要不在棧頂,就是onStop狀態:
3.4.任務棧的id自增長型,是Integer類型。
3.5.新創建Activity會被壓入棧頂。點擊back會將棧頂Activity彈出,並產生新的棧頂元素作為顯示界面(onResume狀態)。
3.6.當Task最后一個Activity被銷毀時,對應的應用程序被關閉,清除Task棧,但是還會保留應用程序進程(狂點Back退出到Home界面后點擊Menu會發現還有這個App的框框。個人理解應該是這個意思),再次點擊進入應用會創建新的Task棧。
- Activity的affinity:
4.1.affinity是Activity內的一個屬性(在ManiFest中對應屬性為taskAffinity)。默認情況下,擁有相同affinity的Activity屬於同一個Task中。
4.2.Task也有affinity屬性,它的affinity屬性由根Activity(創建Task時第一個被壓入棧的Activity)決定。
4.3.在默認情況下(我們什么都不設置),所有的Activity的affinity都從Application繼承。也就是說Application同樣有taskAffinity屬性。
<application android:taskAffinity="gf.zy"
4.4.Application默認的affinity屬性為Manifest的包名。
暫時就是這么多了,如果還有不妥的地方我會補充的。接下來我們來正式看Activity的啟動模式:
二、Activity啟動模式:
1. 默認啟動模式standard:
該模式可以被設定,不在manifest設定時候,Activity的默認模式就是standard。在該模式下,啟動的Activity會依照啟動順序被依次壓入Task中:
上面這張圖講的已經很清楚了,我想應該不用做什么實驗來論證了吧,這個是最簡單的一個,我們過。
2. 棧頂復用模式singleTop:
在該模式下,如果棧頂Activity為我們要新建的Activity(目標Activity),那么就不會重復創建新的Activity。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="zy.pers.activitytext">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:taskAffinity="gf.zy"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".TwoActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="ONETEXT_TWOACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ThreeActivity">
<intent-filter>
<action android:name="ONETEXT_THREEACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
這是我的第一個應用OneText的Mainfest結構,里面創建了三個Activity,我們把第二個Activity的模式設置為singleTop。
每個Activity界面都只有一個顯示當前界面名稱的TextView和一個用來組跳轉的Button,所以應用OneText的功能就是從活動1跳轉到活動2,活動2繼續跳轉活動2,代碼就不給大家展示了,都能寫出來。
我們發現在我們跳轉到TwoActivity之后,點擊跳轉新的TwoActivity時候,他沒有響應。
為了作對比,我們再把TwoActivity設置為standard,看一看效果:
我們發現創建了很多的TwoActivity。
同時我們打印上task的Id(我沒有把所有周期方法都打印log):
發現他們全部都是來自一個Task。這個可以過。
應用場景:
開啟渠道多,適合多應用開啟調用的Activity:通過這種設置可以避免已經創建過的Activity被重復創建(多數通過動態設置使用,關於動態設置下面會詳細介紹)
3. 棧內復用模式singleTask:
與singleTop模式相似,只不過singleTop模式是只是針對棧頂的元素,而singleTask模式下,如果task棧內存在目標Activity實例,則:
- 將task內的對應Activity實例之上的所有Activity彈出棧。
- 將對應Activity置於棧頂,獲得焦點。
同樣我們也用代碼來實現一下這個過程:
還是剛才的那一坨代碼,只是我們修改一下Activity1的模式為singleTask,然后讓Activity2跳轉到Activity3,讓Activity3跳轉到Activity1:
在跳回MainActivity之后點擊back鍵發現直接退出引用了,這說明此時的MainActivity為task內的最后一個Activity。所以這個模式過。
應用場景:
程序主界面,我們肯定不希望主界面被多創建,而且在主界面退出的時候退出整個App是最好的設想。
耗費系統資源的Activity:對於那些及其耗費系統資源的Activity,我們可以考慮將其設為singleTask模式,減少資源耗費(在創建階段耗費資源的情況,個人理解-。+)。
4.全局唯一模式singleInstance:
這是我們最后的一種啟動模式,也是我們最惡心的一種模式:在該模式下,我們會為目標Activity分配一個新的affinity,並創建一個新的Task棧,將目標Activity放入新的Task,並讓目標Activity獲得焦點。新的Task有且只有這一個Activity實例。 如果已經創建過目標Activity實例,則不會創建新的Task,而是將以前創建過的Activity喚醒(對應Task設為Foreground狀態)
我們為了看的更明確,這次不按照上圖的步驟設計程序了(沒錯,這幾張圖都不是我畫的-。+!)。
我們先指定一下這次的程序:還是這三個Activity,這次Activity3設置為singleInstance,1和2默認(standard)。
然后我們看一下這個效果:
說一下我們做了什么操作:
首先由1創建2,2創建3,然后又由3創建2,2創建3,3創建2,然后一直back,圖如下:
還請各位別嫌棄我-。+,圖雖然不好看,但是很生動形象。。。。具體說一下:這張圖對應着我們上面的程序流程,黃色的代表Background的Task,藍色的代表Foreground的Task。
我們發現back的時候會先把Foreground的Task中的Activity彈出,直到Task銷毀,然后才將Background的Task喚到前台,所以最后將Activity3銷毀之后,會直接退出應用。
但是有沒有想過這樣會出現一個問題,什么問題我們直接看圖就好: