如何使用保存实例状态保存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

相关文章
相关标签/搜索