重學安卓:絕不丟失狀態的 Activity 重建機制!

KunMinX發表於2019-06-17

前言的前言

很抱歉上週我因為沉迷程式碼而忘了發文。

重學安卓:絕不丟失狀態的 Activity 重建機制!

今天和大家分享的這篇,原本是《重學安卓》付費專欄連載的第三篇,沒想到在我這幾天業餘時間獨立開發的小應用《JDGD》中,連續遇上了 7 處 “狀態重建” 的場景!

考慮到我在 <掘金> 等熱門技術社群 發文的目標是,提供 “從 0 到 1”、易於理解和貫通的 擺渡文,致力於為讀者撥開迷霧、建立感性認識。

因而 原味的、硬核的、鑽研細節的 文章,我多是在小眾的付費技術社群釋出。對此感興趣的朋友請不要慌,文末連結給出 ?

重學安卓:絕不丟失狀態的 Activity 重建機制!

JDGD 的頁面結構是,最外層由一個 Activity 裝載著一個 ContainerFragment,然後 ContainerFragment 中又裝載了 3 個 ChildFragment。相當於是個 3 層巢狀頁面結構。

使用者平時可以操作的,就是在這 3 個 ChildFragment 之間來回切換。並且當發生旋轉螢幕時,來自 3 個層次的 5 個頁面都會發生重建。

重學安卓:絕不丟失狀態的 Activity 重建機制!

這要是換做以前的話,我八成是會被難住,因為我司的產品,手機端是固定豎屏,平板端是固定橫屏,即使開啟了旋轉螢幕模式,也不會走重建的流程,因而多年來我都沒有鑽研過這個問題。

並且,網路上關於重建的文章 多是人云亦云、含糊不清,並沒有把最關鍵的細節給講明白、講透,導致我最開始也在 半吊子文章中 白費不少時間。

重學安卓:絕不丟失狀態的 Activity 重建機制!

好在上上星期,我親自覆盤和實證了 “狀態重建” 的知識點,於是這回遇上的幾個問題,都是輕輕鬆鬆地得到化解 ?。

考慮到頁面重建和狀態管理,真的是每個人都必然會遇到的問題,於是我就 破例 地將 Activity 狀態重建的知識,無保留地分享給大家。

已經付費的小夥伴們請不要擔心,今天僅僅是通過介紹 Activity 的重建,來奠定對重建的認知基礎,真正的好戲還在後頭 ~

還沒閱讀過的小夥伴也不要著急,正由於今天講的是基礎,即使只看這篇,你也沒有白來

前言

很高興見到你!

上一期,我在發表的 《重學安卓:Activity 生命週期的 3 個闢謠》 中,通過介紹網上 99% 的文章都不曾解析過的 “程式模式”,來幫助大家深入理解 Activity 生命週期 的設計依據、存在意義 及 注意事項。

並且,文末我還針對網文的 3 個訛傳,來給大家闢了謠。

相信經過這樣一次介紹,你對生命週期擁有了相比其他人更加深刻的認識。?

那麼這一期,我們來結合現實的案例,來講解一下 Activity 的重建機制。

文章目錄一覽

  • 前言
  • 因為心裡沒底,而不敢用的狀態恢復
  • 什麼是重建?引發重建的場景有哪些?
  • 為何要設計出重建的機制?有何好處?
  • 狀態儲存和恢復的具體過程?(99% 的網文遺漏的關鍵細節)
  • 狀態儲存和恢復的的注意事項?
  • 如何避免 “配置發生變化” 導致的重建?
  • 綜上

因為心裡沒底,而不敢用的狀態恢復

就在上週五,我司向客戶推送了 App 新版本,原以為萬事大吉,畢竟經過了一週的打磨,各項功能都已趨於流暢穩定,沒想到,在客戶近乎變態的資料操作下,有客戶反映 “頁面切換巨卡”、“速度巨慢”。

重學安卓:絕不丟失狀態的 Activity 重建機制!

為何會產生這種情況呢?我找到編寫該頁面的同事詢問了緣由。

同事說,問題在於每次 onPause 時,為了避免App 切到後臺被系統回收導致資料丟失,而做了大量的資料持久化操作。

那為什麼不直接通過 Activity 的狀態管理機制 來管理臨時資料呢?

同事說,那東西“不靠譜”,用著感覺心裡沒底。

重學安卓:絕不丟失狀態的 Activity 重建機制!

…… 是網上介紹 Activity 重建流程和狀態管理的文章不夠多嗎?不是的,網文都有提到:當發生重建時,就會走 onSaveInstanceState 和 onRestoreInstanceState,

然而卻沒有一篇深入地探究過:當走 onSaveInstanceState 和 onRestoreInstanceState 時,過程中究竟經歷了哪些細節、背後 決定狀態被成功儲存和恢復的關鍵條件 到底是怎樣的。

這使得讀者在使用這個機制時忐忑不安,無法 100% 確定不會出事。

重學安卓:絕不丟失狀態的 Activity 重建機制!

於是在經過原始碼分析和再三的實測檢驗後,我將 “重建機制” 及 “狀態管理機制” 的內容整理成這篇文章。

如果閱讀完本文後,你對二者的緣起、規律有了明確的認識,從而 100% 放心地在日後工作中使用,那我的這番功夫就沒白費 ~

什麼是重建?引發重建的場景有哪些?

正常的生命週期流程,是頁面從正常建立到銷燬全流程。

而重建流程,則是在特定條件下,引發頁面被銷燬,並再次被建立的流程。

通常是 “系統資源的回收” 或 “配置發生變化” 導致的重建

劃重點 ? ? ?

系統資源回收是指:

當 App 處於背景模式時,可能因系統記憶體不足而被回收。

例如按下 Home 鍵切回桌面,或是接電話跳轉到電話程式,都有可能使此前的這個 App 處於背景模式。

配置發生變化是指:

當系統配置發生變化時,比如螢幕方向、語言的改變。

為何要設計出重建的機制?有何好處?

一來: 對於資源回收的情況,儲存狀態並等到使用時再恢復,要比後臺存留程式 所佔的資源要小得多

二來: 對於配置變化的情況,比如當螢幕方向發生變化時,唯有重建,才有機會載入不同的檢視,如果橫豎屏的佈局不同的話。

狀態儲存和恢復的具體過程?

首先,“狀態” 是指支撐 UI 介面內容展示的臨時資料。

比如 EditText 中的文字、CheckBox 的勾選與否。

有且只有引發重建時,Activity 會走 onSaveInstanceState 和 onRestoreInstanceState,來儲存和恢復狀態。

onSaveInstanceState 執行在 onStop 之前,onRestoreInstanceState 執行在 onStart 之後。

其次,Activity 有兩個資料結構用於儲存狀態:

一個是 View States,專門用於儲存 View 的狀態;

再一個是 Instance States,用於儲存 View States 以及 開發者在 onSaveInstanceState 中手動儲存的 Activity 成員變數。

重學安卓:絕不丟失狀態的 Activity 重建機制!

在引發重建時,Activity 會自動為我們儲存和恢復 View 的狀態。具體表現為:

Activity 在 onSaveInstanceState 時,會 自動收集 View Hierachy 中每一個 “實現了狀態儲存和恢復方法” 的 View 的狀態,這些狀態資料會在 onRestoreInstanceState 時回傳給每一個 View。並且回傳時是依據 View 的 id 來逐一匹配的。

劃重點 ? ? ?

其中,View 的狀態資料會被收集到 View States 中,View States 也會隨著 Activity 中其他被指定收集的成員變數,一同被收集到 Instance States 中,等待恢復時逐個恢復。

狀態儲存和恢復的的注意事項?

簡言之:

1.為了成功儲存狀態,要求在 View 內部實現狀態儲存和恢復方法

原生的 View 都有做到;如果是自定義 View,務必記住這一點;如果第三方 View 沒做到,可以通過繼承其來實現儲存和恢復方法。

2.為了成功恢復狀態,要求在佈局中給 View 賦予相應的 id

劃重點 ? ? ?

3.如果是 Activity 的成員變數,需要額外在 Activity(子類)中重寫 onSaveInstanceState 和 onRestoreInstanceState 方法

注意:

Activity 中重寫僅僅是為了額外地儲存成員變數。重寫方法時,記得要保留基類(super)的實現,Activity 正是在基類中完成 View 狀態的儲存和恢復

劃重點 ? ? ?

如何避免 “配置發生變化” 導致的重建?

在清單檔案中為該 Activity 配置 android:configChanges 屬性。

比如屬性值 orientation|screenSize 對應著旋轉螢幕,locale 對應著語言變化。

如此,在配置發生變化時,不會導致重建,而是走 onConfigurationChanged 回撥。

綜上

只要遵循 《狀態儲存和恢復的的注意事項》一節所提到的關鍵細節,就能穩妥地儲存和恢復狀態。

你再也不用為了臨時資料而在 onPause 或 onStop 中執行重量級的持久化儲存操作啦!

xzl短

看不過癮?這裡只為你 而準備了一份 簡潔有力的 《重學安卓》認知地圖 ?

相關文章