我一直在研究Android SDK平臺,但還不清楚如何保存應用程序的狀態。 所以,考慮到「 Hello,Android」示例的次要從新設計,請執行如下操做: html
package com.android.hello; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class HelloAndroid extends Activity { private TextView mTextView = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mTextView = new TextView(this); if (savedInstanceState == null) { mTextView.setText("Welcome to HelloAndroid!"); } else { mTextView.setText("Welcome back."); } setContentView(mTextView); } }
我認爲這對於最簡單的狀況就足夠了,可是不管我如何離開應用程序,它老是以第一條消息作出響應。 android
我確信解決方案就像覆蓋onPause
或相似的東西同樣簡單,可是我已經在文檔中花了30分鐘左右的時間,而且沒有發現任何明顯的問題。 數據庫
onSaveInstanceState(bundle)
和onRestoreInstanceState(bundle)
方法僅在旋轉屏幕(方向更改) onRestoreInstanceState(bundle)
對數據持久性有用。
它們在應用程序之間切換時甚至都很差(由於調用了onSaveInstanceState()
方法,可是再也不再次調用onCreate(bundle)
和onRestoreInstanceState(bundle)
。
要得到更多持久性,請使用共享首選項。 閱讀這篇文章 app
這是Android開發的經典「陷阱」。 這裏有兩個問題: 框架
瀏覽全部這些線程,我懷疑開發人員在不少時候會同時談論這兩個不一樣的問題……所以,全部的混淆和報告「這對我都不起做用」。 ide
首先,要闡明「預期」行爲:onSaveInstance和onRestoreInstance是脆弱的,僅適用於瞬態。 預期的用途(輔助)是在旋轉手機(方向更改)時處理「活動」娛樂。 換句話說,預期的用法是您的活動在邏輯上仍處於「最重要」的位置,但仍必須由系統從新實例化。 保存的Bundle不會持久保存在process / memory / gc以外,所以,若是您的活動進入後臺,您將不能真正依賴於此。 是的,也許您的Activity的內存將在進入後臺並逃脫GC後倖存下來,但這是不可靠的(也不是可預測的)。 this
所以,若是您遇到在應用程序的「啓動」之間存在有意義的「用戶進度」或狀態的狀況,那麼指南就是使用onPause和onResume。 您必須本身選擇並準備一個持久性存儲。 google
可是-有一個很是使人困惑的錯誤,使全部這些問題變得複雜。 詳細信息在這裏: spa
http://code.google.com/p/android/issues/detail?id=2373 線程
http://code.google.com/p/android/issues/detail?id=5277
基本上,若是您的應用程序是使用SingleTask標誌啓動的,而後在之後從主屏幕或啓動器菜單啓動它,則隨後的調用將建立一個NEW任務……您將有效地擁有應用程序的兩個不一樣實例居住在同一個堆棧中...很快就會變得很是奇怪。 這彷佛是在開發過程當中啓動應用程序時發生的(即從Eclipse或Intellij),所以開發人員常常遇到這種狀況。 並且還能夠經過某些應用商店更新機制(所以也會影響您的用戶)。
在乎識到本身的主要問題是此錯誤而不是預期的框架行爲以前,我在這些線程中進行了數小時的奮戰。 一個偉大的文章和 解決方法 (更新:見下文)彷佛來自用戶@kaciula在此答案中:
2013年6月更新 :幾個月後,我終於找到了「正確的」解決方案。 您不須要本身管理任何有狀態的startedApp標誌,您能夠從框架中檢測到此問題並適當地保釋。 我在LauncherActivity.onCreate的開始附近使用它:
if (!isTaskRoot()) { Intent intent = getIntent(); String action = intent.getAction(); if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) { finish(); return; } }
savedInstanceState
僅用於保存與Activity的當前實例相關聯的狀態,例如當前的導航或選擇信息,所以,若是Android銷燬並從新建立Activity,它能夠像之前同樣返回。 請參閱文檔onCreate
和onSaveInstanceState
對於更長的狀態,請考慮使用SQLite數據庫,文件或首選項。 請參閱保存持久狀態 。
您須要重寫onSaveInstanceState(Bundle savedInstanceState)
並將要更改的應用程序狀態值寫入Bundle
參數,以下所示:
@Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate if the process is // killed and restarted. savedInstanceState.putBoolean("MyBoolean", true); savedInstanceState.putDouble("myDouble", 1.9); savedInstanceState.putInt("MyInt", 1); savedInstanceState.putString("MyString", "Welcome back to Android"); // etc. }
Bundle本質上是一種存儲NVP(「名稱-值對」)映射的方法,它將被傳入onCreate()
和onRestoreInstanceState()
,而後您將在其中提取以下值:
@Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // Restore UI state from the savedInstanceState. // This bundle has also been passed to onCreate. boolean myBoolean = savedInstanceState.getBoolean("MyBoolean"); double myDouble = savedInstanceState.getDouble("myDouble"); int myInt = savedInstanceState.getInt("MyInt"); String myString = savedInstanceState.getString("MyString"); }
一般,您將使用此技術來存儲應用程序的實例值(選擇,未保存的文本等)。
個人問題是我僅在應用程序生命週期內須要持久性(即一次執行,包括在同一應用程序中啓動其餘子活動並旋轉設備等)。 我嘗試了上述答案的各類組合,但並無在全部狀況下都獲得我想要的東西。 最後,對我有用的是在onCreate期間獲取對savedInstanceState的引用:
mySavedInstanceState=savedInstanceState;
並在須要時使用它來獲取變量的內容,大體以下:
if (mySavedInstanceState !=null) { boolean myVariable = mySavedInstanceState.getBoolean("MyVariable"); }
我按照上面的建議使用onSaveInstanceState
和onRestoreInstanceState
,可是我想我也能夠或者在改變變量時使用個人方法來保存變量(例如,使用putBoolean
)