使用onSaveInstanceState和onRestoreInstanceState來保存恢復被系統銷燬的數據

開發項目時有遇到這樣一個問題:程序長時間打開,使用一會其他應用或者打開比較佔內存的應用後,再次回到開發的項目,程序就會崩潰,查看錯誤信息是NullPointException。到底是爲什麼呢?經過我跟另一個同事長期觀察、測試、總結髮現我們在項目中使用了大量的靜態變量,報錯的地方都是使用了靜態變量。

空異常的原因應該是java虛擬機的垃圾回收機制主動回收沒有被引用的對象,在內存不足的時候,虛擬機主動回收處於後臺的Activity、Service,所以當再次回到這個頁面的時候,數據已經被回收,沒有恢復,所以報NullPointException。

在這篇文章中http://blog.csdn.net/weihan1314/article/details/8033052作者遇到與我們相同的問題,靜態變量使用誤區。
如果不是用全局靜態變量,那在Activity或其他組件中怎麼使用全局變量呢?在android中還有一個組件——Application,它是與應用同時存在的,也就是應用在它就在,並不會被GC給莫名其妙的回收掉,在android application學習
這篇文章中介紹了怎麼安全的使用全局變量。

但是現在的問題是,我們的應用都已經快完工,如果把全局變量都修改,感覺不現實。這將是一個巨大的工程。於是繼續看帖學習。發現了Activity中的兩個方法onSaveInstanceState和onRestoreInstanceState這兩個方法。

不屬於Activity生命週期中的方法。它們不同於 onCreate()、onPause()等生命週期方法,它們並不一定會被觸發。當應用遇到意外情況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity時,onSaveInstanceState() 會被調用。但是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。因爲在這種情況下,用戶的行爲決定了不需要保存Activity的狀態。通常onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。

  在activity被殺掉之前調用保存每個實例的狀態,以保證該狀態可以在onCreate(Bundle)或者onRestoreInstanceState(Bundle) (傳入的Bundle參數是由onSaveInstanceState封裝好的)中恢復。這個方法在一個activity被殺死前調用,當該activity在將來某個時刻回來時可以恢復其先前狀態。 


那麼我是怎麼使用這兩個方法來保存我想要的數據呢?看一下代碼:

 

/**
  * 保存狀態
  */
 @Override
 protected void onSaveInstanceState(Bundle outState) {
 
  String json_user = JSONUtils.toJson(Constants.USER);	//把要保存的靜態全局變量先轉成Json
  outState.putString("json_user", json_user);  
  super.onSaveInstanceState(outState);
 }

 /**
  * 恢復數據
  * @param savedInstanceState
  */
 public void resaveInstanceState(Bundle savedInstanceState){
   if (savedInstanceState == null) {
   return;
  }
   String json_user = savedInstanceState.getString("json_user");
   if(json_user != null && !json_user.equals("")){
    Constants.USER = JSONUtils.fromJson(json_user, User.class);
   }
}

然後很重要的一個步驟是在 onCreate方法中初始化 resaveInstanceState(savedInstanceState)這個方法,這個方法是自定義的方法。

@Override
 protected void onCreate(Bundle savedInstanceState) {
  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  super.onCreate(savedInstanceState);
  resaveInstanceState(savedInstanceState);
  init();
 }



如果使用Activity中onRestoreInstanceState(Bundle savedInstanceState) 方法有個弊端是,每次恢復數據前是先onCreate()Activity 的,所以對於我們遇到的問題還是沒有解決,如果想要用封裝好的方法,又要修改很多數據,給需要恢復數據的地方放個默認值。當調用onRestoreInstanceState(Bundle savedInstanceState)方法後再刷新頁面。

 @Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onRestoreInstanceState(savedInstanceState);
 }


所以用了自定義的方法自定義方法也有個弊端,就是當activity調用onPause()方法時數據就會被恢復。


發佈了39 篇原創文章 · 獲贊 6 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章