編輯:關於Android編程
本文實例講述了Android編程實現狀態保存的方法。分享給大家供大家參考,具體如下:
1、當我們正在發短信的時候,已經寫了幾百字了,這時突然來了一個電話,我們接完電話之後,如果發現辛辛苦苦的幾百字不見了,那可就火大了,而實際上這些內容都是保存了的。在我們接電話的過程中,我們發信息的那個Activity是可能會被系統回收的,這時會調用Activity的onSaveInstanceState回調方法,而我們就可以在這個方法中保存狀態數據,在onCreate方法或者在2.0之後提供的回調方法onRestoreInstanceState中進行狀態數據恢復。
2、當我們在玩游戲的時候,可能又想聽歌,然後我們會按home或者back鍵退出游戲去啟動音樂,然後再回到游戲,當我們回到游戲的時候,發現剛剛的狀態還是被保存的。這種情況,我們可以這樣保存狀態。在onPause方法中保存狀態數據,在onResume方法中進行狀態恢復。
activity的狀態是被保留在內存中的,當resume時,它會立即開始執行。
當用戶在開啟一個新activity時,當前的activity可能在內存中處於停止狀態也可能由於新activity需要更多內存而被系統殺掉了,但不論怎樣,當用戶在新activity上按返回鍵時,他希望看到的是原先的activity的界面。原先的activity如果是被重新創建,那麼它要恢復到用戶最後看到它的樣子。那麼我們怎麼做呢?其實也不難,跟據上一節所述,在onPause()
或onStop()
或onDestyroy()
中保存必要的數據就行了。但是現在google又冒出一個新的東西:onSaveInstanceState()
,觀其名可知其意:它是專門用來保存實例狀態的,這個“實例”不是指的activity對象,而是它所在的進程,因為activity的銷毀是因為它所在的進程被殺而造成的。onSaveInstanceState()是在系統感覺需要殺死activity時調用的,它被傳入一個參數:Bundle,這個Bundle可以被認為是個map,字典之類的東西,用”鍵-值”來保存數據。那麼什麼狀態叫做感覺要被殺死呢?
官方文檔原話:
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還沒有被銷毀,而僅僅是一種可能性。這種可能性有哪些?通過重寫一個activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我們可以清楚地知道當某個activity(假定為activity A)顯示在當前task的最上層時,其onSaveInstanceState方法會在什麼時候被執行,有這麼幾種情況:
1、當用戶按下HOME鍵時。這是顯而易見的,系統不知道你按下HOME後要運行多少其他的程序,自然也不知道activity A是否會被銷毀,故系統會調用onSaveInstanceState,讓用戶有機會保存某些非永久性的數據。以下幾種情況的分析都遵循該原則
2、長按HOME鍵,選擇運行其他的程序時。
3、按下電源按鍵(關閉屏幕顯示)時。
4、從activity A中啟動一個新的activity時。
5、屏幕方向切換時,例如從豎屏切換到橫屏時。在屏幕切換之前,系統會銷毀activity A,在屏幕切換之後系統又會自動地創建activity A,所以onSaveInstanceState一定會被執行
總而言之,onSaveInstanceState的調用遵循一個重要原則,即當系統“未經你許可”時銷毀了你的activity,則onSaveInstanceState會被系統調用,這是系統的責任,因為它必須要提供一個機會讓你保存你的數據(當然你不保存那就隨便你了)。
至於onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成對的被調用的。
onRestoreInstanceState被調用的前提是,activity A“確實”被系統銷毀了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被調用,例如,當正在顯示activity A的時候,用戶按下HOME鍵回到主界面,然後用戶緊接著又返回到activity A,這種情況下activity A一般不會因為內存的原因被系統銷毀,故activity A的onRestoreInstanceState方法不會被執行
另外,onRestoreInstanceState的bundle參數也會傳遞到onCreate方法中,你也可以選擇在onCreate方法中做數據還原。
那麼,不是可以在onPause()中保存數據嗎?為什麼又搞出這樣一個家伙來?它們之間是什麼關系呢?原來onSaveInstanceState()的主要目的是保存activity的狀態有關的數據,當系統在殺死activity時,如果它希望activity下次出現的樣子跟現在完全一樣,那麼它就調用這個onSaveInstanceState(),否則就不調用。所以要明白這一點:onSaveInstanceState()並不是永遠都會調用。比如,當用戶在一個activity上按返回時,就不會調用,因為用戶此時明確知道這個activity是要被銷毀的,並不期望下次它的樣子跟現在一樣(當然開發者可以使它保持臨死時的表情,你非要這樣做,系統也沒辦法),所以就不用調用onSaveInstanceState()。現在應該明白了:在onPause(),onStop()以及onDestroy()中需要保存的是那些需要永久化是數據,而不是保存用於恢復狀態的數據,狀態數據有專門的方法:onSaveInstanceState()。
數據保存在一個Bundle中,Bundle被系統永久化。當再調用activity的onCreate()時,原先保存的bundle就被傳入,以恢復上一次臨死時的模樣,如果上次死時沒有保存Bundle,則為null。
還沒完呢,如果你沒有實現自己的onSaveInstanceState(),但是activity上控件的樣子可能依然能被保存並恢復。原來activity類已實現了onSaveInstanceState(),在onSaveInstanceState()的默認實現中,會調用所有控件的相關方法,把控件們的狀態都保存下來,比如EditText中輸入的文字,CheckBox是否被選中等等。然而不是所有的控件都能被保存,這取決於你是否在layout文件中為控件賦了一個名字(android:id)。有名的就存,無名的不管。
既然有現成的可用,那麼我們到底還要不要自己實現onSaveInstanceState()?這得看情況了,如果你自己的派生類中有變量影響到UI,或你程序的行為,當然就要把這個變量也保存了,那麼就需要自己實現,否則就不需要,但大多數情況肯定需要自己實現一下下了。對了,別忘了在你的實現中調用父類的onSaveInstanceState()。
注:由於onSaveInstanceState()並不是每次銷毀時都會調用,所以不要在其中保存那些需要永久化的數據,執行保存那些數據的最好地方是:onPause()中。
測試你程序的狀態恢復能力的最好方法是:旋轉屏幕,每當屏幕的方向改變時,當前的activity就會被系統銷毀,然後重新創建。
示例代碼:
import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.widget.EditText; public class MainActivity extends Activity { //內容輸入框 private EditText content; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); content=(EditText)findViewById(R.id.content); if(savedInstanceState!=null){ //得到保存的數據 String saveString=savedInstanceState.getString("content"); //恢復數據 content.setText(saveString); } } /** * 在該方法中保存狀態數據 */ @Override protected void onPause() { super.onPause(); //得到要保存的輸入框的內容 String saveString=content.getText().toString(); SharedPreferences sp=this.getSharedPreferences("save", Context.MODE_PRIVATE); //保存輸入框的內容 sp.edit().putString("content", saveString).commit(); } /** * 在該方法中恢復狀態數據 */ @Override protected void onResume() { //得到保存的內容 String saveString=this.getSharedPreferences("save", Context.MODE_PRIVATE).getString("content", null); //恢復內容 content.setText(saveString); super.onResume(); } /** * 在該方法中保存狀態數據 */ @Override protected void onSaveInstanceState(Bundle outState) { //得到要保存的輸入框的內容 String saveString=content.getText().toString(); //保存輸入框的內容 outState.putString("content", saveString); super.onSaveInstanceState(outState); } }
更多關於Android相關內容感興趣的讀者可查看本站專題:《Android編程之activity操作技巧總結》、《Android視圖View技巧總結》、《Android操作json格式數據技巧總結》、《Android開發入門與進階教程》、《Android資源操作技巧匯總》及《Android控件用法總結》
希望本文所述對大家Android程序設計有所幫助。
1.寫在前面本篇的主要內容是關於在Dialog中軟鍵盤的顯示與隱藏問題,需求是在Dialog中有一個密碼輸入框,彈出Dialog顯示軟鍵盤,關閉Dialog隱藏軟鍵盤。
1. 第一種,使用 TabHost + ViewPager 實現該方法會有一個Bug,當設置tabHost.setCurrentTab()為0時,ViewPager不顯示
android之文件下載android文件下載有三個要點不能在主線程中下載文件 在配置文件中給定權限 使用http協議的get方法連接網絡下載文件做好這三點就可以成功的下
Android開發四大組件分別是:活動(Activity):用於表現功能。服務(Service):後台運行服務,不提供界面呈現。廣播接收器(BroadcastReceiv