如何使用保存實例狀態保存Android Activity狀態?

我一直在研究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分鐘左右的時間,而且沒有發現任何明顯的問題。 數據庫


#1樓

onSaveInstanceState(bundle)onRestoreInstanceState(bundle)方法僅在旋轉屏幕(方向更改) onRestoreInstanceState(bundle)對數據持久性有用。
它們在應用程序之間切換時甚至都很差(由於調用了onSaveInstanceState()方法,可是再也不再次調用onCreate(bundle)onRestoreInstanceState(bundle)
要得到更多持久性,請使用共享首選項。 閱讀這篇文章 app


#2樓

這是Android開發的經典「陷阱」。 這裏有兩個問題: 框架

  • Android框架存在一個細微的錯誤,至少在舊版本上,該錯誤使開發過程當中的應用程序堆棧管理很是複雜(沒法徹底肯定是否/什麼時候/如何修復)。 我將在下面討論此錯誤。
  • 解決此問題的「正常」或預期方式自己很是複雜,由於onPause / onResume和onSaveInstanceState / onRestoreInstanceState的雙重性

瀏覽全部這些線程,我懷疑開發人員在不少時候會同時談論這兩個不一樣的問題……所以,全部的混淆和報告「這對我都不起做用」。 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在此答案中:

Home鍵按下行爲

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;
    }
}

#3樓

savedInstanceState僅用於保存與Activity的當前實例相關聯的狀態,例如當前的導航或選擇信息,所以,若是Android銷燬並從新建立Activity,它能夠像之前同樣返回。 請參閱文檔onCreateonSaveInstanceState

對於更長的狀態,請考慮使用SQLite數據庫,文件或首選項。 請參閱保存持久狀態


#4樓

您須要重寫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");
}

一般,您將使用此技術來存儲應用程序的實例值(選擇,未保存的文本等)。


#5樓

個人問題是我僅在應用程序生命週期內須要持久性(即一次執行,包括在同一應用程序中啓動其餘子活動並旋轉設備等)。 我嘗試了上述答案的各類組合,但並無在全部狀況下都獲得我想要的東西。 最後,對我有用的是在onCreate期間獲取對savedInstanceState的引用:

mySavedInstanceState=savedInstanceState;

並在須要時使用它來獲取變量的內容,大體以下:

if (mySavedInstanceState !=null) {
   boolean myVariable = mySavedInstanceState.getBoolean("MyVariable");
}

我按照上面的建議使用onSaveInstanceStateonRestoreInstanceState ,可是我想我也能夠或者在改變變量時使用個人方法來保存變量(例如,使用putBoolean

相關文章
相關標籤/搜索