activity state save

2024-06-11 16:38
文章标签 activity state save

本文主要是介绍activity state save,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android 组件系列-----Activity保存状态

转载 :http://www.cnblogs.com/xiaoluo501395377/p/3418542.html

本篇随笔将详细的讲解Activity保存状态的概念,也就是saving activity state。

一、Activity状态保持概念

保存Activity的状态是非常重要的,例如我们在玩一个游戏的时候,突然来了一个电话,这个时候在接听完电话之后我们返回到游戏中,这个时候我们希望游戏还是之前那个进度,或者说发生突发事件,游戏这个应用程序被关闭了,这个时候我们如果再重新打开游戏的话,我们如果还是希望回到之前的进度,我们就需要将其状态保存起来,这样在Activity的摧毁时,我们还能够根据保存的状态回到之前的进度。这就是Activity的状态保存。

二、两种方式的情况下Activity的状态会被保存

Activity的状态被保存通常有两种方式,我们首先通过android的官方文档提供的图来看一下这两种方式:

1.当一个Activity位于另一个Activity的前面时,也就是另一个Activity处于stop状态,这个时候这个Activity仍然占用着内存,并且保持着Activity的状态,如果此时点击后退按钮,那么此时第一个Activity又会重新回到前台界面上,此时这个Activity会保持原来的状态,我们不需要重新获得其状态。

2.当我们的这个Activity处于stop状态在后台时,如果此时有一个优先级别更高的Activity需要获得资源,此时系统可能会破坏处于stop状态的Activity,回收其内存,此时这个Activity对象会被destroyed,此时如果我们必须调用一个 onSaveInstanceState() 方法来保存我们的Activity的对象状态。

onSaveInstanceState(Bundle outState)这个方法接受一个Bundle类型参数,我们可以将我们需要保存的状态通过Bundle的 putString, putInt 方法保存起来。

当我们的Activity处于极易被摧毁的时候,系统会调用 onSaveInstanceState() 方法,如果此时系统杀死了这个Activity的线程,这个Activity对象被destroy后,再打开这个Activity时,又会重新创建这个Activity,这个时候系统会将 onSaveInstanceState 方法中的 Bundle 对象传递给Activity的 onCreate()和 onRestoreInstanceState() 方法,

使用这两个方法中的任何一个,我们都可以根据之前保存的 Bundle 对象来恢复我们Activity之前的状态。

三、onSaveInstanceState方法

protected void onSaveInstanceState (Bundle outState)

下面我们具体看看这个方法,通过这个方法我们可以在一个Activity被杀死时,并在将来如果要重新创建这个Activity时可以恢复其保存的状态。我们不需要疑惑这个方法和Activity生命周期函数方法的调用时期,例如onPause()方法,当一个Activity处于后台时或者容易受到破坏时,这个方法就会被调用。

有两种情况是不会调用这个onSaveInstanceState方法的:

①activity B 位于 activity A的前面,此时如果点击 Back 按钮,activity B 会分别调用 onPause、onStop方法,此时系统并不会调用 onSaveInstanceState() 方法,因为此时是我们显示的关闭activity B,所以系统认为调用 onSaveInstanceState() 是没有并要的。

②activity B 位于 activity A的前面,此时activity A处于后台状态,但是还是占用了内存资源,当通过Back 按钮,使得activity A重新回到前台时,onSaveInstanceState()方法也是没有必要调用的,因为此时activity A本身就完整的保存了当前的状态。

 

接下来我们通过一个实例来看看通过Activity的 onSaveInstanceState() 、onCreate()以及onRestoreInstanceState()方法的调用来保持我们Activity的状态。

复制代码
public class ThirdActivity extends Activity
{private final String TAG = "ThirdActivity";private Button button;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.third);Log.i(TAG, "ThirdActivity onCreate");if(savedInstanceState != null){String name = (String)savedInstanceState.getString("name");Toast.makeText(ThirdActivity.this, "onCreate --->  " + name, 1).show();}button = (Button)findViewById(R.id.button);button.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View view){Intent intent = new Intent();intent.setClass(ThirdActivity.this, FourthActivity.class);startActivity(intent);}});}@Overrideprotected void onStart(){super.onStart();Log.i(TAG, "ThirdActivity onStart");}@Overrideprotected void onResume(){super.onResume();Log.i(TAG, "ThirdActivity onResume");}@Overrideprotected void onPause(){super.onPause();Log.i(TAG, "ThirdActivity onPause");}@Overrideprotected void onSaveInstanceState(Bundle outState){super.onSaveInstanceState(outState);Log.i(TAG, "ThirdActivity onSaveInstanceState");outState.putString("name", "xiaoluo");}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState){super.onRestoreInstanceState(savedInstanceState);Log.i(TAG, "ThirdActivity onRestoreInstanceState");if(savedInstanceState != null){String name = (String)savedInstanceState.getString("name");Toast.makeText(ThirdActivity.this, "onRestoreInstanceState ---> " + name, 1).show();}}@Overrideprotected void onStop(){super.onStop();Log.i(TAG, "ThirdActivity onStop");}@Overrideprotected void onRestart(){super.onRestart();Log.i(TAG, "ThirdActivity onRestart");}@Overrideprotected void onDestroy(){super.onDestroy();Log.i(TAG, "ThirdActivity onDestroy");}
}
复制代码

我们看到,在这个Activity中,我们实现了其 onSaveInstanceState()、onCreate()和onRestoreInstanceState()方法,我们在 onSaveInstanceState() 方法中将当前的Activity的状态保存下来:

复制代码
    @Overrideprotected void onSaveInstanceState(Bundle outState){super.onSaveInstanceState(outState);Log.i(TAG, "ThirdActivity onSaveInstanceState");outState.putString("name", "xiaoluo");}    
复制代码

然后在onCreate()方法和onRestoreInstanceState() 方法中试图得到保存的Bundle对象,当Activity第一次被创建的时候,onCreate()和onRestoreInstanceState()方法中的Bundle对象是null的

复制代码
protected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.third);Log.i(TAG, "ThirdActivity onCreate");if(savedInstanceState != null){String name = (String)savedInstanceState.getString("name");Toast.makeText(ThirdActivity.this, "onCreate --->  " + name, 1).show();}button = (Button)findViewById(R.id.button);button.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View view){Intent intent = new Intent();intent.setClass(ThirdActivity.this, FourthActivity.class);startActivity(intent);}});}
复制代码
复制代码
@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState){super.onRestoreInstanceState(savedInstanceState);Log.i(TAG, "ThirdActivity onRestoreInstanceState");if(savedInstanceState != null){String name = (String)savedInstanceState.getString("name");Toast.makeText(ThirdActivity.this, "onRestoreInstanceState ---> " + name, 1).show();}}
复制代码

我们在这两个方法里分别使用 Toast 的弹出框来看看是否能将Bundle保存的状态值打印出来。我们为了模拟这个实验,需要通过将手机屏幕的横竖屏进行切换。

当屏幕的方向被改变的时候,系统会首先destroy然后recreate这个Activity对象来根据我们配置的资源文件重新加载界面,这个时候保存我们的Activity的状态是非常重要的,因为在大多数情况下,屏幕放心的改变是经常发生的事,所以这个时候我们必须通过 onSaveInstanceState() 方法来保存我们的Activity的状态。

我们来看看实验结果:

我们看到,当我们反转屏幕的时候,因为之前已经通过 onSaveInstanceState()方法保存了Activity的状态,所以在Activity从destroy到recreate时,会将保存的Bundle对象传给onCreate和onRestoreInstanceState方法,此时我们就能够恢复我们Activity的状态了。

四、Android View控件的onSaveInstanceState()方法

当我们在创建一个Activity对象的时候,我们如果没有重写父类的 onSaveInstanceState()方法,此时我们的一些Activity状态也会通过调用父类Activity的默认的 onSaveInstanceState()方法来保存下来。特别地:父类的onSaveInstanceState()方法会调用布局文件中每一个View对象的相应的 onSaveInstanceState()方法 来保持各自的状态。在Android的大多数的widget控件都非常好的实现了 onSaveInstanceState()方法,因此我们对这些空间的值的改变都会被自动的保存下来。例如我们的EditText、Checkbox控件,当我们在输入了我们的值只会,当Activity被destroy-->recreate的时候,此时我们的值仍然会被保存下来,前提是如果我们需要保存一个View控件的状态,我们必须要给其指定一个唯一的标识符(通过 android:id 属性来指定),如果我们没有指定的话,系统则不会保存其状态。例如我们来看一下下面这个例子:

复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><TextView android:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20sp"android:text="usenrame"/><EditText android:id="@+id/username"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_toRightOf="@id/textView1"android:inputType="text"/><TextView android:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/username"android:textSize="20sp"android:text="email"/><EditText android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/username"android:layout_toRightOf="@id/textView2"android:inputType="textEmailAddress"/><CheckBox android:id="@+id/checkBox1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="100dp"android:text="篮球"/><CheckBox android:id="@+id/checkBox2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/checkBox1"android:layout_alignTop="@id/checkBox1"android:text="足球"/><CheckBox android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/checkBox2"android:layout_alignTop="@id/checkBox1"android:text="网球"/></RelativeLayout>
复制代码

我们这个Activity的界面一共有5个View控件,其中username这个EditText我们指定了ID,email这个EditText没有指定ID,而下面的三个CheckBox,只有最后一个CheckBox没有为其指定ID,我们来看看,当这个Activity被重新创建时,其会不会保存每个View控件的状态:

我们在两个文本框中输入了值,然后将三个CheckBox都勾选上,此时我们翻转我们的屏幕:

我们看到,因为username这个EditText和前两个CheckBox我们给其指定了ID,所以系统会调用其 onSaveInstanceState() 方法来保存我们的View控件状态,而对于email这个EditText和最后一个CheckBox,我们没有指定ID标识符,所以系统不会自动为其保存状态。

注意:尽管默认的Activity的onSaveInstanceState() 方法会保存我们的View控件的状态,但是我们仍然推荐重新其onSaveInstanceState() 方法来保存我们额外的一些Activity的状态,在分别重写 onCreate()、onSaveInstanceState() 和 onRestoreInstanceState()方法时,我们要首先调用父类的方法才行,这样就会默认的保存我们View控件的状态了

最后再总结一句:因为 onSaveInstanceState() 方法不能保证一定会被调用,所以我们在onSaveInstanceState() 方法中只能用来保存我们的Activity的临时的状态信息,而对于要持久化保存的对象或状态,我们应该在 onPause() 方法中来做

网友评论:

1、保存状态是要在程序不可见时完成的, 当程序重新可见时需要做的操作时读取之前保存的状态。
   就是说在onPause中保存状态,在onResume中重新加载状态。

2、 因为如果程序正常pause正常stop的话,用onPause()保存游戏变量是没问题的,适合持久性数据的保存,
比如按返回按钮退出应用,保存游戏状态情况下。但是在某些情况下是不合适的,比如说当程序的activity不在栈顶时候,恰好系统内存不足了,就会销毁后台某个不可见的activity,将该activity彻底从内存中销毁,这个时候是不调用onPause()方法的,这个时候保存游戏状态的方法是调用onSaveInstance()。这种方式是用bundle保存在内存中,然后在下次启动activity的时候,onCreate(bundle)参数中的bundle就是刚保存的bundle对象,所以这种情况适合保存临时性数据状态。单纯从这点来看,在onStart()或者onResume()保存状态也是可以的,但是楼上那哥们说的好,activity还没获得焦点没来得及跟用户交互怎么个保存状态。。。

这篇关于activity state save的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1051711

相关文章

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

iptables持久化命令:netfilter-persistent save

在Linux上,使用netfilter-persistent命令可以保存iptables防火墙规则,确保它们在系统重启后仍然有效。以下是如何使用netfilter-persistent来保存iptables规则的步骤: 打开终端:首先,你需要打开Linux系统的终端。保存规则:使用netfilter-persistent save命令可以保存当前的iptables规则。这个命令会调用所有插件,将

LeakCanary测试app内存泄露+registerActivityLifecycleCallbacks管理Activity的生命周期

public class MyApplication extends Application {private String tag = "MyApplication";private static Stack<Activity> activityStack;//检测内存泄露private RefWatcher refWatcher;@Overridepublic void onCreate()

android studio怎么修改创建的Activity的模板?

1.找到android studio的安装目录,如下图,找到对应文件,修改EmptyActivity的模板。 2.修改成如下: 3.新建的EmptyActivity的默认代码如下:

Apache-Flink深度解析-State

来源:https://dwz.cn/xrMCqbk5 Flink系列精华文章合集入门篇: Flink入门Flink DataSet&DataSteam APIFlink集群部署Flink重启策略Flink分布式缓存Flink重启策略Flink中的TimeFlink中的窗口Flink的时间戳和水印Flink广播变量Flink-Kafka-connetorFlink-Table&SQLFlink

Flink使用Broadcast State实现流处理配置实时更新

大数据技术与架构 点击右侧关注,大数据开发领域最强公众号! 暴走大数据 点击右侧关注,暴走大数据! 本文作者时延军发表在http://shiyanjun.cn,如果你也在使用Broadcast State,那么可以参考一下。 Broadcast State是Flink支持的一种Operator State。使用Broadcast State,可以在Flink程序的一个Stream中输入数

Activity转屏重建之 Activity.onConfigurationChanged

偶尔也会遇到由于转屏引起的一些问题。 有些时候,并不希望由于转屏使得Activity取重建。 再如键盘消失后的重建。 下面以一个demo为例子,小小总结一下用法。 如果想在转屏后,屏幕上立马打印出当前处于什么横竖屏状态 1.都知道有个属性android:configChanges可以用来定义什么情况下可以使得Activity不会restart。 android:configC

查看当前正在运行的Activity列表

1、在终端中输入, 注意adb如果没有配置到系统环境变量里,则需要cd到它所在的文件夹下 “adb shell dumpsys activity” 2、出来的结果比较多,直接搜索"Running" ,找到 Running activities (most recent first):       TaskRecord{4069c020 #4 A shy.luo.ta

Activity被回收导致其内部的Fragment

方式一:   MainActivity重写onSaveInstanceState方法,将super.onSaveInstanceState(outState);注释掉,让其不再保存Fragment的状态,达到其随着MainActivity一起被回收的效果! 方式二: @Overrideprotected void onSaveInstanceState(Bundle outSta

Android canvas save restore saveLayer的异同点

一、基础操作 drawText、drawRect、drawColor等 对于这些基础操作,相信每一个安卓开发者都能说上个一二点出来,这些就不多做介绍,api 工程师必备技能之一。 在进阶之前,先回答这个问题:    问:canvas既然大家都理解为画布,那如果先在画布上绘制了某些内容,然后再canvas.rotate旋转了画布,为什么这些已经绘制在画布上的内容不会跟随着旋转?    答:由此可