Activity 異常生命週期
說道Activity的生命週期相信所有Android開發者都耳熟能詳,但那些只是一般情況下,除此以外Activity還存在異常情況的生命週期。
造成異常情況的發生主要分爲以下兩種:1、用戶操作導致。2、系統自願發生改變及內存不足。
Activity狀態和內存的關係
系統會在需要釋放內存的時候殺死進程,一個進程是否會被系統殺死取決於當時的狀態,而進程的狀態往往取決於其Activity的狀態。以下是幾種常見的狀態和其對應的情況:
Likelihood of being killed | Process state | Activity state |
---|---|---|
Least | Foreground (having or about to get focus) | Created Started Resumed |
More | Background (lost focus) | Paused |
Most | Background (not visible) | Stopped |
Most | Empty | Destroyed |
可以看出,當Activity處於後臺時其進程都是有可能被殺掉的。
Activity和系統配置
理解這個問題,首先要對系統的資源加載機制有一定了解,舉個栗子,Activity中加載圖片,通常會將圖片保存在項目drawable目錄中通過resources進行獲取,Android爲了兼容不同版本所有資源文件都有資源限定符的概念,不清楚的可以看Android資源限定符。這樣,當應用啓動時就會根據當前設備的情況去加載合適的Resource資源了。
比如,橫豎屏可能會拿到兩張不同的圖片,因此,當Activity在運行中突然發生屏幕旋轉情況時,由於系統配置發生了改變,默認情況Activity就會被銷燬,當然也可以通過配置阻止銷燬,這是後話了。
Activity的異常重建
異常重建的主要方式
上面說到了Activity發生異常銷燬的兩種可能,那爲什麼有時即便被銷燬了我們依然可以重新看到界面呢,這就是Android的異常重建機制了。
爲了保證用戶體驗,當Activity是在異常情況下終止時系統會調用採用狀態保存和回覆兩套流程來恢復之前的狀態。
onSaveInstanceState
保存狀態,該方法在onStop
之前,無論是否發生異常均會調用該方法。onRestoreInstanceState
恢復狀態,該方法在onStart
之後,僅發生異常時調用。除此之外,我們熟悉的onCreate(savedInstanceState: Bundle?)
也有類似的功能,其中參數savedInstanceState
就是保存的狀態。
異常重新的具體流程
通過onSavedInstanceState
和onRestoreInstanceState
,系統自動爲我們做了一定的恢復工作,例如文本框的數據,ListView滾動位置等等。那這些具體是如何實現的呢?
首先是Activity被意外終止,調用onSave..
去保存數據,然後Activity會委託Window,Window再委託其上的頂級容器,通常頂級容器就是我們知道的DecorView
。最後由DecorView
遍歷自身子元素去一一保存數據。因此特定View
的數據保存和恢復其實是View自身實現的。查看頂級View的源碼,發現一樣具備onSave..
和onRestore..
兩個方法,也就是說如果我們需要對某個View的異常狀態進行保存,只需要重寫其onSave..
和onRestore..
兩個方法就可以了。
重建範例
View的重建主要是通過兩個主方法中savedInstanceState: Bundle?
參數完成的。以下是官方文檔中舉得例子:
companion object {
val STATE_SCORE = "playerScore"
val STATE_LEVEL = "playerLevel"
}
override fun onSaveInstanceState(outState: Bundle?) {
// Save the user's current game state
outState?.run {
putInt(STATE_SCORE, currentScore)
putInt(STATE_LEVEL, currentLevel)
}
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(outState)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
with(savedInstanceState) {
// Restore value of members from saved state
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState)
// Restore state members from saved instance
savedInstanceState?.run {
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
}