一般來說, 調(diào)用onPause()和onStop()方法后的activity實例仍然存在于內(nèi)存中, activity的所有信息和狀態(tài)數(shù)據(jù)不會消失, 當activity重新回到前臺之后, 所有的改變都會得到保留. 但是當系統(tǒng)內(nèi)存不足時, 調(diào)用onPause()和onStop()方法后的activity可能會被系統(tǒng)摧毀, 此時內(nèi)存中就不會存有該activity的實例對象了. 如果之后這個activity重新回到前臺, 之前所作的改變就會消失. 為了避免此種情況的發(fā)生, 開發(fā)者可以覆寫onSaveInstanceState()方法. onSaveInstanceState()方法接受一個Bundle類型的參數(shù), 開發(fā)者可以將狀態(tài)數(shù)據(jù)存儲到這個Bundle對象中, 這樣即使activity被系統(tǒng)摧毀, 當用戶重新啟動這個activity而調(diào)用它的onCreate()方法時, 上述的Bundle對象會作為實參傳遞給onCreate()方法, 開發(fā)者可以從Bundle對象中取出保存的數(shù)據(jù), 然后利用這些數(shù)據(jù)將activity恢復到被摧毀之前的狀態(tài).
示例:
public class MainActivity extends Activity
{
public static final int SECOND_ACTIVITY = 0;
private String temp;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 從savedInstanceState中恢復數(shù)據(jù), 如果沒有數(shù)據(jù)需要恢復savedInstanceState為null
if (savedInstanceState != null) {
temp = savedInstanceState.getString("temp");
System.out.println("onCreate: temp = " + temp);
}
}
public void onResume() {
super.onResume();
temp = "xing";
System.out.println("onResume: temp = " + temp);
// 切換屏幕方向會導致activity的摧毀和重建
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
System.out.println("屏幕切換");
}
}
// 將數(shù)據(jù)保存到outState對象中, 該對象會在重建activity時傳遞給onCreate方法
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("temp", temp);
}
}
需要注意的是, onSaveInstanceState()方法并不是一定會被調(diào)用的, 因為有些場景是不需要保存狀態(tài)數(shù)據(jù)的. 比如用戶按下BACK鍵退出activity時, 用戶顯然想要關閉這個activity, 此時是沒有必要保存數(shù)據(jù)以供下次恢復的, 也就是onSaveInstanceState()方法不會被調(diào)用. 如果調(diào)用onSaveInstanceState()方法, 調(diào)用將發(fā)生在onPause()或onStop()方法之前.
onSaveInstanceState()方法的默認實現(xiàn) 如果開發(fā)者沒有覆寫onSaveInstanceState()方法, 此方法的默認實現(xiàn)會自動保存activity中的某些狀態(tài)數(shù)據(jù), 比如activity中各種UI控件的狀態(tài). android應用框架中定義的幾乎所有UI控件都恰當?shù)膶崿F(xiàn)了onSaveInstanceState()方法, 因此當activity被摧毀和重建時, 這些UI控件會自動保存和恢復狀態(tài)數(shù)據(jù). 比如EditText控件會自動保存和恢復輸入的數(shù)據(jù), 而CheckBox控件會自動保存和恢復選中狀態(tài). 開發(fā)者只需要為這些控件指定一個唯一的ID(通過設置android:id屬性即可), 剩余的事情就可以自動完成了. 如果沒有為控件指定ID, 則這個控件就不會進行自動的數(shù)據(jù)保存和恢復操作. 由上所述, 如果開發(fā)者需要覆寫onSaveInstanceState()方法, 一般會在第一行代碼中調(diào)用該方法的默認實現(xiàn): super.onSaveInstanceState(outState).
是否需要覆寫onSaveInstanceState()方法 既然該方法的默認實現(xiàn)可以自動的保存UI控件的狀態(tài)數(shù)據(jù), 那什么時候需要覆寫該方法呢? 如果需要保存額外的數(shù)據(jù)時, 就需要覆寫onSaveInstanceState()方法. 如需要保存類中成員變量的值(見上例).
onSaveInstanceState()方法適合保存什么數(shù)據(jù) 由于onSaveInstanceState()方法方法不一定會被調(diào)用, 因此不適合在該方法中保存持久化數(shù)據(jù), 例如向數(shù)據(jù)庫中插入記錄等. 保存持久化數(shù)據(jù)的操作應該放在onPause()中. onSaveInstanceState()方法只適合保存瞬態(tài)數(shù)據(jù), 比如UI控件的狀態(tài), 成員變量的值等.
引發(fā)activity摧毀和重建的其他情形 除了系統(tǒng)處于內(nèi)存不足的原因會摧毀activity之外, 某些系統(tǒng)設置的改變也會導致activity的摧毀和重建. 例如改變屏幕方向(見上例), 改變設備語言設定, 鍵盤彈出等.