Android中突發情況Activity數據的保存和恢復


Android中突發情況Activity數據的保存和恢復

寫在前面:
在我們的APP使用的過程中,總有可能出現各種手滑、被壓在后台、甚至突然被殺死的情況。所以對APP中一些臨時數據或關鍵持久型數據,就需要我們使用正確的方式進行保存或恢復。

突發情況都有哪些?

因為本文討論的是當一些突發情況的出現時,對數據的保存和恢復。所以現在總結一下突發情況應該都有哪些?

      • 點擊back鍵

      • 點擊鎖屏鍵

      • 點擊home鍵

      • 其他APP進入前台

      • 啟動了另一個Activity

      • 屏幕方向旋轉

      • APP被Kill

當這些突發情況發生的時候,有哪些關鍵的方法會被調用呢?

寫了一個簡單的demo,我用上述的突發情況進行測試,代碼中我重寫了所有Activity的生命周期方法onSaveInstanceState方法,並打印對應的log在控制台,下面是demo圖:
demo圖
部分代碼示例

這里就不貼出測試的過程了,直接來告訴大家測試的結果吧:

當我的APP處在前台,能與用戶交互的情況下,出現上述的突發事件時,只有點擊back鍵onSaveInstanceState方法不會調用。其余的情況下, 該方法一律都會調用,這又是為什么呢?並且onPause方法是必然會調用的,這又給我們保存數據提供了怎樣的思路呢?

onSaveInstanceState

好吧,相信當你看到本文標題的時候,你就應該想到了這個方法。因為當我們學習Android基礎知識時,用onSaveInstanceState方法進行數據恢復是你必然學到過的。所以前面我營造出的一些懸念看似是失敗了,不過對於onSaveInstanceState你理應知道更多知識:

      1. 何時調用:
> Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother
calling it when the instance is actually being destroyed by a user
action (such as pressing the BACK key)

找到了以上一段話,翻譯過來就是當某個activity變得“容易”被系統銷毀時,該activity的onSaveInstanceState就會被執行,除非該activity是被用戶主動銷毀的,例如當用戶按BACK鍵的時候。

結合我們以上的例子,其實都在說明一個詞,就是**被動**。當Activity並不是由我主動點擊back鍵而喪失焦點時,onSaveInstanceState方法就一定會調用。就例如我上述列舉的那些除了點擊back鍵的“**突發情況**”。
      1. 何地調用:
        何地調用

        在我寫的這個demo中,onSaveInstanceState的調用是處於onPauseonStop之間的,(下面關於Activity的生命周期方法,會講解一些值得大家注意的),我查閱了一下資料,能保證的是onSaveInstanceState方法會在onStop之前調用,但是是否在onPause之前就不一定了。

結論: google工程師們對onSaveInstanceState如此設計就是讓其完成對一些臨時的、非永久數據存儲並進行恢復。什么樣的數據屬於臨時數據呢?舉個例子,比如EditText中輸入的內容,CheckBox是否勾選,ScrollView的滑動位置,目前視頻的播放位置等等。

當我還沒有自學Android時,玩着一些APP就會產生一個疑問,比如我在一個輸入框中輸入了大量文字沒有提交或者保存。此時來了一個電話,如果退回的時候,輸入框里面的文字消失了,那我可能會砸了電話,所以這個保存數據的操作,是Android開發者做的嗎?

然而是不需要的,因為Android的View本身自己就實現了onSaveInstanceState方法,這些控件自己就具有保存臨時數據和恢復臨時數據的能力。

例如TextView中的部分源碼:

TextView中的實現

其他View控件都有相似的實現原理。值得一提的是,只有當你給這個wiget在xml中指定id時,它才具有保存數據並且恢復的能力,並且不同的wiget還不能共用這個id,否則會出現數據覆蓋的情況。具體的源碼有興趣大家可以自己去看,這里因為篇幅的原因不再貼出,關於onSaveInstanceState我們先說這些,趕緊看看使用姿勢。

onSaveInstanceState的使用姿勢

比如我們要保存當前視頻的播放進度,這個顯然控件沒有幫我們實現onSaveInstanceState,所以就只能靠自己了,代碼如下所示。

保存臨時數據
恢復臨時數據

當在onCreate取出臨時數據時,記得加一個非空判斷

看到這里,也許你認為本文該就此結束了,不過在回過頭看看,我們剛才一直強調的是臨時數據,畢竟onSaveInstanceState本身就是為臨時數據服務的,但是一些永久性質的數據,比如插入數據庫的操作,我們應該在什么方法中對其進行保存呢?

onPause

在介紹onPause方法之前,還是想聊聊Activity的生命周期方法,相信大家對它應該有了初步的了解,不過在相應的生命周期方法中,我們應該做什么操作呢?推薦給大家一篇文章,我覺得不錯。

Activity生命周期詳解

關於onPause,我找到了一下關於它的特性:

onPause(), onStop(), onDestroy() are “killable after” lifecycle methods. This indicates whether or not the system can kill the process hosting the activity at any time after the method returns, without executing another line of the activity’s code. Because onPause() is the first of the three, once the activity is created, onPause() is the last method that’s guaranteed to be called before the process can be killed—if the system must recover memory in an emergency, then onStop() and onDestroy() might not be called. Therefore, you should use onPause() to write crucial persistent data (such as user edits) to storage. However, you should be selective about what information must be retained during onPause(), because any blocking procedures in this method block the transition to the next activity and slow the user experience.

翻譯過來就是:無論出現怎樣的情況,比如程序突然死亡了,能保證的就是onPause方法是一定會調用的,而onStop和onDestory方法並不一定,所以這個特性使得onPause是持久化相關數據的最后的可靠時機。當然onPause方法不能做大量的操作,這會影響下一個Activity入棧。

剛才我們的測試結果還說明了一個道理,onSaveInstanceState並不是百分百調用的(比如點擊了back鍵),顯然一些永久性的數據,我們並不能在此中保存。

關於本文的結論就顯而易見了,我們來一句話總結一下:

臨時數據使用onSaveInstanceState保存恢復,永久性數據使用onPause方法保存。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM