Activity是什麼?
相信大家都知道Android中的4大組件(Activity
活動,Service
服務,ContentProvider
內容提供者,BroadcastReceiver
廣播接收器),Activity
是我們使用最多的也是最基本的組件,Activity
提供窗口和用戶進行交互.
Android中的activity
全都歸屬於task
管理(task
是一個具有棧結構的容器),task
是多個activity
的集合,android默認情況會爲每個App
維持一個task
來存放app
的所有activity
(當然這只是默認情況),task
的默認name
爲該app
的packagename
(包名)
當然我們也可以在AndroidMainfest.xml
中申明activity
的 taskAffinity 屬性來自定義task
,但是不建議使用,因爲如果其他app也申明瞭同樣的task
,那個app
可能啓動到你的activity
,這樣會帶來各種安全問題(比如拿到你的Intent
).
Activity的內部調用
上面我們介紹過了,系統是通過task
(棧)的方式來管理activity的,當一個新的activity開始的時候,該activity
會被放置在堆棧(back
stack
)的頂部,成爲正在運行的活動,之前的activity始終保持低於它在堆棧,而不會出現在前臺.
官方activity_lifecycle:
當我們打開一個新的activity
實例的時候,系統會以此調用
onCreate() -> onStart() -> onResume() 然後開始running
當activity
在running的時候如果被覆蓋(打開新的activity,或者被鎖屏,但是它依然在前臺運行,lost
focus but is still visible),系統就會調用onPause()
;
在
onpause()
方法中,我們通常會提交未保存的更改到持久化數據,停止動畫和其他東西.但是我們要知道現在這個activity還是完全活着(它保存所有的狀態和成員信息,並且保存到窗口管理器的連接)
- 1.啓動
Activity
:系統會先調用onCreate
方法,然後調用onStart
方法,最後調用onResume
,Activity
進入運行狀態。 - 2.當前
Activity
被其他Activity
覆蓋其上或被鎖屏:系統會調用onPause
方法,暫停當前Activity
的執行。 - 3.當前
Activity
由被覆蓋狀態回到前臺或解鎖屏:系統會調用onResume
方法,再次進入運行狀態。 - 4.當前
Activity
轉到新的Activity
界面或按Home
鍵回到主屏,自身退居後臺:系統會先調用onPause
方法,然後調用onStop
方法,進入停滯狀態。 - 5.用戶後退回到此
Activity
:系統會先調用onRestart
方法,然後調用onStart
方法,最後調用onResume
方法,再次進入運行狀態。 - 6.當前
Activity
處於被覆蓋狀態或者後臺不可見狀態,即第2步和第4步,系統內存不足,殺死當前Activity,而後用戶退回當前Activity
:再次調用onCreate
方法、onStart
方法、onResume
方法,進入運行狀態。 - 7.用戶退出當前
Activity
:系統先調用onPause
方法,然後調用onStop
方法,最後調用onDestory
方法,結束當前Activity
。
onSaveInstanceState
:(1)在Activity被覆蓋或退居後臺之後,系統資源不足將其殺死,此方法會被調用;(2)在用戶改變屏幕方向時,此方法會被調用;(3)在當前Activity
跳轉到其他Activity
或者按Home
鍵回到主屏,自身退居後臺時,此方法會被調用。第一種情況我們無法保證什麼時候發生,系統根據資源緊張程度去調度;第二種是屏幕翻轉方向時,系統先銷燬當前的Activity
,然後再重建一個新的,調用此方法時,我們可以保存一些臨時數據;第三種情況系統調用此方法是爲了保存當前窗口各個View
組件的狀態。onSaveInstanceState
的調用順序是在onPause
之前。
onRestoreInstanceState
:(1)在Activity
被覆蓋或退居後臺之後,系統資源不足將其殺死,然後用戶又回到了此Activity
,此方法會被調用;(2)在用戶改變屏幕方向時,重建的過程中,此方法會被調用。我們可以重寫此方法,以便可以恢復一些臨時數據。onRestoreInstanceState
的調用順序是在onStart
之後。
activity被回收的狀態和信息保存和恢復過程
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
if(savedInstanceState!=null){ //判斷是否有以前的保存狀態信息
savedInstanceState.get("Key");
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
//可能被回收內存前保存狀態和信息,
Bundle data = new Bundle();
data.putString("key", "last words before be kill");
outState.putAll(data);
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// TODO Auto-generated method stub
if(savedInstanceState!=null){ //判斷是否有以前的保存狀態信息
savedInstanceState.get("Key");
}
super.onRestoreInstanceState(savedInstanceState);
}
}
onSaveInstanceState()
方法,在activity
被回收之前調用,用來保存自己的狀態信息,以便回收後重建時恢復數據(在onCreate()
或onRestoreInstanceState()
中恢復).旋轉屏幕重建activity會調用該方法,但其他情況在onRause()
和onStop()
狀態的activity不一定會調用,
下面是官方文檔說明:
One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.
也就是說,系統靈活的來決定會不會調用該方法,但是如果要調用就一定發生在onStop
方法之前,但不保證發生在onPase的前面還是後面.
onRestoreInstanceState()
該方法在onstart
和onPostCreate
之間調用,當然我們也可以在onCreat中恢復之前我們在onSaveInstanceState()
中保存下來的數據,但是我們有時候需要在初始化佈局完成之後再恢復數據,這是就可以在onRestoreInstanceState()
中恢復數據.onPostCreate()
:一般我們都沒有實現這個方法,它的作用是在代碼開始運行之前,調用系統做最後的初始化工作.
關於啓動模式
啓動模式是什麼?
簡單點說就是:定義activity實例與task的關聯方式
爲什麼我們要定義啓動模式呢?
爲了實現默認啓動(
standard
)模式之外的需求:
- 讓某個
activity
啓動一個新的task
(而不是被放入當前task
) - 讓activity啓動時只調用已有的某個實例(而不是在back stack(之前我們有提到過喲) 頂創建一個新的實例)
- 當用戶離開task時只想保留根
activity
,而back stack
中的其他activity都要清空.
怎樣定義啓動模式
定義啓動模式的方法有2種:
- 使用
manifest
文件定義 - 使用
Intent
標誌定義
使用manifest文件定義啓動模式:
在 manifest 文件中activity聲明時,利用 activity 元素的 launchMode 屬性來設定 activity 與 task 的關係。
<activity
......
android:launchMode="standard"
>
.......
</activity>
注意: 你用 launchMode 屬性爲 activity 設置的模式可以被啓動 activity 的 intent 標誌所覆蓋,代碼的優先級最高。
現在我們知道了怎麼定義啓動模式了,但是有哪些啓動模式呢?
standard
(默認模式)
當通過這種模式啓動activity時,Android總會爲目標 Activity創建一個新的實例(之前有過也會重新創建),並將該Activity添加到當前Task棧中。這種方式不會啓動新的Task,只是將新的 Activity添加到原有的Task中。
singleTop
該模式和standard模式基本一致,但有一點不同:當將要被啓動的Activity已經位於Task棧頂時,系統不會重新創建目標Activity實例,而是直接複用Task棧頂的Activity。
singleTask
Activity在同一個Task內只有一個實例。
如果將要啓動的Activity不存在,那麼系統將會創建該實例,並將其加入Task棧頂;
如果將要啓動的Activity已存在,且存在棧頂,直接複用Task棧頂的Activity。
如果Activity存在但是沒有位於棧頂,那麼此時系統會把位於該Activity上面的所有其他Activity全部移出Task,從而使得該目標Activity位於棧頂。
singleInstance
無論從哪個Task中啓動目標Activity,只會創建一個目標Activity實例且會用一個全新的Task棧來裝載該Activity實例(全局單例).
如果將要啓動的Activity不存在,那麼系統將會先創建一個全新的Task,再創建目標Activity實例並將該Activity實例放入此全新的Task中。
如果將要啓動的Activity已存在,那麼無論它位於哪個應用程序,哪個Task中;系統都會把該Activity所在的Task轉到前臺,從而使該Activity顯示出來。
和"singleTask"類似,唯一不同的是系統不會在這個activity的實例所在的task中啓動任何其他activity。
這個activity的實例永遠是這個task中的唯一一個成員,這個activity啓動的任何其他activity都將在另外的task中打開。
使用Intent標識定義啓動模式:
FLAG_ACTIVITY_NEW_TASK
和之前討論過的"singleTask"相同,在新的task中啓動activity,如果一個你需要的activity的task已經存在,則將它推向前臺,恢復其上一個狀態,它通過onNewIntent()收到這個新的intent。-
FLAG_ACTIVITY_SINGLE_TOP
和"singleTop"行爲相同,如果被啓動的activity是當前頂部的activity,則已經存在的實例收到 onNewIntent()
,而不是新建實例。 -
FLAG_ACTIVITY_CLEAR_TOP
如果被啓動的activity已經在當前task運行,不創建它的新實例,而是銷燬在它之上的其他所有activities,然後通過 onNewIntent()
傳遞一個新的intent給這個恢復了的activity。
這個行爲在 launchMode 中沒有對應的屬性值。
注意,如果activity的啓動模式是"standard",它自己也將被移除,然後一個新的實例將被啓動。
這是因爲當啓動模式是"standard"時,爲了接收新的intent必須創建新的實例。
處理affinities
Affinity指示了activity更傾向於屬於哪個task。
默認情況下,同一個應用的activities傾向於在同一個task中。你可以通過<activity>標籤中的 taskAffinity 來修改這種行爲。
詳細內容請查看:API Guides: Tasks and Back Stack
http://developer.android.com/guide/components/tasks-and-back-stack.html
開啓一個task
你可以通過給activity一個intent filter(action是"android.intent.action.MAIN",category是"android.intent.category.LAUNCHER"),讓這個activity是一個task的進入點。
如下:
<activity ... >
<intent-filter ... >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...
</activity>
一個這樣的intent filter會使得這個activity的icon和label顯示在程序啓動處,提供了一種方法,使得用戶可以啓動這個activity,當它啓動後,用戶也可以通過它來返回到這個task。
第二個能力是很重要的:用戶必須能夠離開一個task,然後通過activity launcher返回到它。
因爲這個原因,兩個讓activity永遠實例化一個task的啓動模式:"singleTask" 和"singleInstance",應該僅在activity有一個 ACTION_MAIN 和CATEGORY_LAUNCHER filter的時候用它們。