我一直在研究Android SDK平台,但还不清楚如何保存应用程序的状态。 因此,考虑到“ Hello,Android”示例的次要重新设计,请执行以下操作:
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);
}
}
我认为这对于最简单的情况就足够了,但是无论我如何离开应用程序,它总是以第一条消息做出响应。
我确信解决方案就像覆盖onPause或类似的东西一样简单,但是我已经在文档中花了30分钟左右的时间,并且没有发现任何明显的问题。
#1楼
onSaveInstanceState(bundle)和onRestoreInstanceState(bundle)方法仅在旋转屏幕(方向更改) onRestoreInstanceState(bundle)对数据持久性有用。
它们在应用程序之间切换时甚至都不好(因为调用了onSaveInstanceState()方法,但是不再再次调用onCreate(bundle)和onRestoreInstanceState(bundle) 。
要获得更多持久性,请使用共享首选项。 阅读这篇文章
#2楼
这是Android开发的经典“陷阱”。 这里有两个问题:
Android框架存在一个细微的错误,至少在旧版本上,该错误使开发过程中的应用程序堆栈管理非常复杂(无法完全确定是否/何时/如何修复)。 我将在下面讨论此错误。
解决此问题的“正常”或预期方式本身非常复杂,因为onPause / onResume和onSaveInstanceState / onRestoreInstanceState的双重性
浏览所有这些线程,我怀疑开发人员在很多时候会同时谈论这两个不同的问题……因此,所有的混淆和报告“这对我都不起作用”。
首先,要阐明“预期”行为:onSaveInstance和onRestoreInstance是脆弱的,仅适用于瞬态。 预期的用途(辅助)是在旋转手机(方向更改)时处理“活动”娱乐。 换句话说,预期的用法是您的活动在逻辑上仍处于“最重要”的位置,但仍必须由系统重新实例化。 保存的Bundle不会持久保存在process / memory / gc之外,因此,如果您的活动进入后台,您将不能真正依赖于此。 是的,也许您的Activity的内存将在进入后台并逃脱GC后幸存下来,但这是不可靠的(也不是可预测的)。
因此,如果您遇到在应用程序的“启动”之间存在有意义的“用户进度”或状态的情况,那么指南就是使用onPause和onResume。 您必须自己选择并准备一个持久性存储。
但是-有一个非常令人困惑的错误,使所有这些问题变得复杂。 详细信息在这里:
基本上,如果您的应用程序是使用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;
}
}
#3楼
savedInstanceState仅用于保存与Activity的当前实例相关联的状态,例如当前的导航或选择信息,因此,如果Android销毁并重新创建Activity,它可以像以前一样返回。 请参阅文档onCreate和onSaveInstanceState
对于更长的状态,请考虑使用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");
}
我按照上面的建议使用onSaveInstanceState和onRestoreInstanceState ,但是我想我也可以或者在改变变量时使用我的方法来保存变量(例如,使用putBoolean )