Android編程實(shí)現(xiàn)狀態(tài)保存的方法分析
本文實(shí)例講述了Android編程實(shí)現(xiàn)狀態(tài)保存的方法。分享給大家供大家參考,具體如下:
1、當(dāng)我們正在發(fā)短信的時(shí)候,已經(jīng)寫了幾百字了,這時(shí)突然來(lái)了一個(gè)電話,我們接完電話之后,如果發(fā)現(xiàn)辛辛苦苦的幾百字不見了,那可就火大了,而實(shí)際上這些內(nèi)容都是保存了的。在我們接電話的過(guò)程中,我們發(fā)信息的那個(gè)Activity是可能會(huì)被系統(tǒng)回收的,這時(shí)會(huì)調(diào)用Activity的onSaveInstanceState回調(diào)方法,而我們就可以在這個(gè)方法中保存狀態(tài)數(shù)據(jù),在onCreate方法或者在2.0之后提供的回調(diào)方法onRestoreInstanceState中進(jìn)行狀態(tài)數(shù)據(jù)恢復(fù)。
2、當(dāng)我們?cè)谕嬗螒虻臅r(shí)候,可能又想聽歌,然后我們會(huì)按home或者back鍵退出游戲去啟動(dòng)音樂(lè),然后再回到游戲,當(dāng)我們回到游戲的時(shí)候,發(fā)現(xiàn)剛剛的狀態(tài)還是被保存的。這種情況,我們可以這樣保存狀態(tài)。在onPause方法中保存狀態(tài)數(shù)據(jù),在onResume方法中進(jìn)行狀態(tài)恢復(fù)。
activity的狀態(tài)是被保留在內(nèi)存中的,當(dāng)resume時(shí),它會(huì)立即開始執(zhí)行。
當(dāng)用戶在開啟一個(gè)新activity時(shí),當(dāng)前的activity可能在內(nèi)存中處于停止?fàn)顟B(tài)也可能由于新activity需要更多內(nèi)存而被系統(tǒng)殺掉了,但不論怎樣,當(dāng)用戶在新activity上按返回鍵時(shí),他希望看到的是原先的activity的界面。原先的activity如果是被重新創(chuàng)建,那么它要恢復(fù)到用戶最后看到它的樣子。那么我們?cè)趺醋瞿??其?shí)也不難,跟據(jù)上一節(jié)所述,在onPause()
或onStop()
或onDestyroy()
中保存必要的數(shù)據(jù)就行了。但是現(xiàn)在google又冒出一個(gè)新的東西:onSaveInstanceState()
,觀其名可知其意:它是專門用來(lái)保存實(shí)例狀態(tài)的,這個(gè)“實(shí)例”不是指的activity對(duì)象,而是它所在的進(jìn)程,因?yàn)閍ctivity的銷毀是因?yàn)樗诘倪M(jìn)程被殺而造成的。onSaveInstanceState()是在系統(tǒng)感覺(jué)需要?dú)⑺繿ctivity時(shí)調(diào)用的,它被傳入一個(gè)參數(shù):Bundle,這個(gè)Bundle可以被認(rèn)為是個(gè)map,字典之類的東西,用”鍵-值”來(lái)保存數(shù)據(jù)。那么什么狀態(tài)叫做感覺(jué)要被殺死呢?
官方文檔原話:
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)
從這句話可以知道,當(dāng)某個(gè)activity變得“容易”被系統(tǒng)銷毀時(shí),該activity的onSaveInstanceState就會(huì)被執(zhí)行,除非該activity是被用戶主動(dòng)銷毀的,例如當(dāng)用戶按BACK鍵的時(shí)候。注意上面的雙引號(hào),何為“容易”?言下之意就是該activity還沒(méi)有被銷毀,而僅僅是一種可能性。這種可能性有哪些?通過(guò)重寫一個(gè)activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我們可以清楚地知道當(dāng)某個(gè)activity(假定為activity A)顯示在當(dāng)前task的最上層時(shí),其onSaveInstanceState方法會(huì)在什么時(shí)候被執(zhí)行,有這么幾種情況:
1、當(dāng)用戶按下HOME鍵時(shí)。這是顯而易見的,系統(tǒng)不知道你按下HOME后要運(yùn)行多少其他的程序,自然也不知道activity A是否會(huì)被銷毀,故系統(tǒng)會(huì)調(diào)用onSaveInstanceState,讓用戶有機(jī)會(huì)保存某些非永久性的數(shù)據(jù)。以下幾種情況的分析都遵循該原則
2、長(zhǎng)按HOME鍵,選擇運(yùn)行其他的程序時(shí)。
3、按下電源按鍵(關(guān)閉屏幕顯示)時(shí)。
4、從activity A中啟動(dòng)一個(gè)新的activity時(shí)。
5、屏幕方向切換時(shí),例如從豎屏切換到橫屏?xí)r。在屏幕切換之前,系統(tǒng)會(huì)銷毀activity A,在屏幕切換之后系統(tǒng)又會(huì)自動(dòng)地創(chuàng)建activity A,所以onSaveInstanceState一定會(huì)被執(zhí)行
總而言之,onSaveInstanceState的調(diào)用遵循一個(gè)重要原則,即當(dāng)系統(tǒng)“未經(jīng)你許可”時(shí)銷毀了你的activity,則onSaveInstanceState會(huì)被系統(tǒng)調(diào)用,這是系統(tǒng)的責(zé)任,因?yàn)樗仨氁峁┮粋€(gè)機(jī)會(huì)讓你保存你的數(shù)據(jù)(當(dāng)然你不保存那就隨便你了)。
至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成對(duì)的被調(diào)用的。
onRestoreInstanceState被調(diào)用的前提是,activity A“確實(shí)”被系統(tǒng)銷毀了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會(huì)被調(diào)用,例如,當(dāng)正在顯示activity A的時(shí)候,用戶按下HOME鍵回到主界面,然后用戶緊接著又返回到activity A,這種情況下activity A一般不會(huì)因?yàn)閮?nèi)存的原因被系統(tǒng)銷毀,故activity A的onRestoreInstanceState方法不會(huì)被執(zhí)行
另外,onRestoreInstanceState的bundle參數(shù)也會(huì)傳遞到onCreate方法中,你也可以選擇在onCreate方法中做數(shù)據(jù)還原。
那么,不是可以在onPause()中保存數(shù)據(jù)嗎?為什么又搞出這樣一個(gè)家伙來(lái)?它們之間是什么關(guān)系呢?原來(lái)onSaveInstanceState()的主要目的是保存activity的狀態(tài)有關(guān)的數(shù)據(jù),當(dāng)系統(tǒng)在殺死activity時(shí),如果它希望activity下次出現(xiàn)的樣子跟現(xiàn)在完全一樣,那么它就調(diào)用這個(gè)onSaveInstanceState(),否則就不調(diào)用。所以要明白這一點(diǎn):onSaveInstanceState()并不是永遠(yuǎn)都會(huì)調(diào)用。比如,當(dāng)用戶在一個(gè)activity上按返回時(shí),就不會(huì)調(diào)用,因?yàn)橛脩舸藭r(shí)明確知道這個(gè)activity是要被銷毀的,并不期望下次它的樣子跟現(xiàn)在一樣(當(dāng)然開發(fā)者可以使它保持臨死時(shí)的表情,你非要這樣做,系統(tǒng)也沒(méi)辦法),所以就不用調(diào)用onSaveInstanceState()?,F(xiàn)在應(yīng)該明白了:在onPause(),onStop()以及onDestroy()中需要保存的是那些需要永久化是數(shù)據(jù),而不是保存用于恢復(fù)狀態(tài)的數(shù)據(jù),狀態(tài)數(shù)據(jù)有專門的方法:onSaveInstanceState()。
數(shù)據(jù)保存在一個(gè)Bundle中,Bundle被系統(tǒng)永久化。當(dāng)再調(diào)用activity的onCreate()時(shí),原先保存的bundle就被傳入,以恢復(fù)上一次臨死時(shí)的模樣,如果上次死時(shí)沒(méi)有保存Bundle,則為null。
還沒(méi)完呢,如果你沒(méi)有實(shí)現(xiàn)自己的onSaveInstanceState(),但是activity上控件的樣子可能依然能被保存并恢復(fù)。原來(lái)activity類已實(shí)現(xiàn)了onSaveInstanceState(),在onSaveInstanceState()的默認(rèn)實(shí)現(xiàn)中,會(huì)調(diào)用所有控件的相關(guān)方法,把控件們的狀態(tài)都保存下來(lái),比如EditText中輸入的文字,CheckBox是否被選中等等。然而不是所有的控件都能被保存,這取決于你是否在layout文件中為控件賦了一個(gè)名字(android:id)。有名的就存,無(wú)名的不管。
既然有現(xiàn)成的可用,那么我們到底還要不要自己實(shí)現(xiàn)onSaveInstanceState()?這得看情況了,如果你自己的派生類中有變量影響到UI,或你程序的行為,當(dāng)然就要把這個(gè)變量也保存了,那么就需要自己實(shí)現(xiàn),否則就不需要,但大多數(shù)情況肯定需要自己實(shí)現(xiàn)一下下了。對(duì)了,別忘了在你的實(shí)現(xiàn)中調(diào)用父類的onSaveInstanceState()。
注:由于onSaveInstanceState()并不是每次銷毀時(shí)都會(huì)調(diào)用,所以不要在其中保存那些需要永久化的數(shù)據(jù),執(zhí)行保存那些數(shù)據(jù)的最好地方是:onPause()中。
測(cè)試你程序的狀態(tài)恢復(fù)能力的最好方法是:旋轉(zhuǎn)屏幕,每當(dāng)屏幕的方向改變時(shí),當(dāng)前的activity就會(huì)被系統(tǒng)銷毀,然后重新創(chuàng)建。
示例代碼:
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 { //內(nèi)容輸入框 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){ //得到保存的數(shù)據(jù) String saveString=savedInstanceState.getString("content"); //恢復(fù)數(shù)據(jù) content.setText(saveString); } } /** * 在該方法中保存狀態(tài)數(shù)據(jù) */ @Override protected void onPause() { super.onPause(); //得到要保存的輸入框的內(nèi)容 String saveString=content.getText().toString(); SharedPreferences sp=this.getSharedPreferences("save", Context.MODE_PRIVATE); //保存輸入框的內(nèi)容 sp.edit().putString("content", saveString).commit(); } /** * 在該方法中恢復(fù)狀態(tài)數(shù)據(jù) */ @Override protected void onResume() { //得到保存的內(nèi)容 String saveString=this.getSharedPreferences("save", Context.MODE_PRIVATE).getString("content", null); //恢復(fù)內(nèi)容 content.setText(saveString); super.onResume(); } /** * 在該方法中保存狀態(tài)數(shù)據(jù) */ @Override protected void onSaveInstanceState(Bundle outState) { //得到要保存的輸入框的內(nèi)容 String saveString=content.getText().toString(); //保存輸入框的內(nèi)容 outState.putString("content", saveString); super.onSaveInstanceState(outState); } }
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android編程之a(chǎn)ctivity操作技巧總結(jié)》、《Android視圖View技巧總結(jié)》、《Android操作json格式數(shù)據(jù)技巧總結(jié)》、《Android開發(fā)入門與進(jìn)階教程》、《Android資源操作技巧匯總》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- android中Activity詳解(生命周期、以各種方式啟動(dòng)Activity、狀態(tài)保存,完全退出等)
- Android保存Activity狀態(tài)的方法
- Android學(xué)習(xí)小結(jié)之Activity保存和恢復(fù)狀態(tài)
- Android 保存Fragment 切換狀態(tài)實(shí)例代碼
- Android中用onSaveInstanceState保存Fragment狀態(tài)的方法
- 實(shí)例探究Android開發(fā)中Fragment狀態(tài)的保存與恢復(fù)方法
- android初學(xué)者必須掌握的Activity狀態(tài)的四大知識(shí)點(diǎn)(必讀)
- Android編程實(shí)現(xiàn)隱藏狀態(tài)欄及測(cè)試Activity是否活動(dòng)的方法
- Android中檢查、監(jiān)聽電量和充電狀態(tài)的方法
- Android中監(jiān)聽軟鍵盤顯示狀態(tài)實(shí)現(xiàn)代碼
相關(guān)文章
Android編程開發(fā)之多點(diǎn)觸摸(Multitouch)實(shí)現(xiàn)方法
這篇文章主要介紹了Android編程開發(fā)之多點(diǎn)觸摸(Multitouch)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了Android多點(diǎn)觸摸的相關(guān)實(shí)現(xiàn)步驟與操作技巧,需要的朋友可以參考下2016-08-08android編程實(shí)現(xiàn)為程序創(chuàng)建快捷方式的方法
這篇文章主要介紹了android編程實(shí)現(xiàn)為程序創(chuàng)建快捷方式的方法,實(shí)例分析了Android創(chuàng)建程序快捷方式的相關(guān)設(shè)置與功能實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-11-11Kotlin啟動(dòng)協(xié)程的三種方式示例詳解
這篇文章主要為大家介紹了Kotlin啟動(dòng)協(xié)程的三種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12基于Android實(shí)現(xiàn)桌面懸浮清內(nèi)存app概述
最近沒(méi)有項(xiàng)目做,于是寫了個(gè)小程序練練手,android桌面懸浮清內(nèi)存app概述,感興趣的朋友一起學(xué)習(xí)吧2015-12-12詳解Android中的NestedScrolling機(jī)制帶你玩轉(zhuǎn)嵌套滑動(dòng)
這篇文章主要給大家詳細(xì)解析了Android中的NestedScrolling機(jī)制,通過(guò)介紹該機(jī)制帶你玩轉(zhuǎn)Android中的嵌套滑動(dòng)效果,文中給出了詳細(xì)的示例代碼和介紹,需要的朋友們可以參考學(xué)習(xí),下面來(lái)一起看看吧。2017-05-05Android入門之使用eclipse進(jìn)行源碼開發(fā)的方法
這篇文章主要介紹了Android入門之使用eclipse進(jìn)行源碼開發(fā)的方法,較為詳細(xì)的分析了使用eclipse進(jìn)行Android源碼開發(fā)的具體步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-02-02Android調(diào)用系統(tǒng)自帶的分享功能實(shí)例代碼
本篇文章主要介紹了Android調(diào)用系統(tǒng)自帶的分享功能實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04eclipse中運(yùn)行monkeyrunner腳本之環(huán)境搭建(4)
這篇文章主要為大家詳細(xì)介紹了eclipse中運(yùn)行monkeyrunner腳本之環(huán)境搭建的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12