我一直在研究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
)