【转】Android 组件系列-----Activity保存状态

时间:2021-12-27 21:04:38

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

一、Activity状态保持概念

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

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

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

【转】Android 组件系列-----Activity保存状态

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的状态。

【转】Android 组件系列-----Activity保存状态
public class ThirdActivity extends Activity
{
private final String TAG = "ThirdActivity";
private Button button;
@Override
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()
{
@Override
public void onClick(View view)
{
Intent intent = new Intent();
intent.setClass(ThirdActivity.this, FourthActivity.class);
startActivity(intent);
}
}); } @Override
protected void onStart()
{
super.onStart();
Log.i(TAG, "ThirdActivity onStart");
} @Override
protected void onResume()
{
super.onResume();
Log.i(TAG, "ThirdActivity onResume");
} @Override
protected void onPause()
{
super.onPause();
Log.i(TAG, "ThirdActivity onPause");
} @Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Log.i(TAG, "ThirdActivity onSaveInstanceState");
outState.putString("name", "xiaoluo");
} @Override
protected 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();
}
} @Override
protected void onStop()
{
super.onStop();
Log.i(TAG, "ThirdActivity onStop");
} @Override
protected void onRestart()
{
super.onRestart();
Log.i(TAG, "ThirdActivity onRestart");
} @Override
protected void onDestroy()
{
super.onDestroy();
Log.i(TAG, "ThirdActivity onDestroy");
}
}
【转】Android 组件系列-----Activity保存状态

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

【转】Android 组件系列-----Activity保存状态
    @Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Log.i(TAG, "ThirdActivity onSaveInstanceState");
outState.putString("name", "xiaoluo");
}
【转】Android 组件系列-----Activity保存状态

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

【转】Android 组件系列-----Activity保存状态
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()
{
@Override
public void onClick(View view)
{
Intent intent = new Intent();
intent.setClass(ThirdActivity.this, FourthActivity.class);
startActivity(intent);
}
}); }
【转】Android 组件系列-----Activity保存状态
【转】Android 组件系列-----Activity保存状态
@Override
protected 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();
}
}
【转】Android 组件系列-----Activity保存状态

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

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

我们来看看实验结果:

【转】Android 组件系列-----Activity保存状态【转】Android 组件系列-----Activity保存状态

【转】Android 组件系列-----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 属性来指定),如果我们没有指定的话,系统则不会保存其状态。例如我们来看一下下面这个例子:

【转】Android 组件系列-----Activity保存状态
<?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>
【转】Android 组件系列-----Activity保存状态

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

【转】Android 组件系列-----Activity保存状态

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

【转】Android 组件系列-----Activity保存状态

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

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

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

from:http://www.cnblogs.com/xiaoluo501395377/p/3418542.html

【转】Android 组件系列-----Activity保存状态的更多相关文章

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

    本篇随笔将详细的讲解Activity保存状态的概念,也就是saving activity state. 一.Activity状态保持概念 保存Activity的状态是非常重要的,例如我们在玩一个游戏的 ...

  2. Android组件系列----Activity组件详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  3. Android 组件系列-----Activity生命周期

    本篇随笔将会深入学习Activity,包括如何定义多个Activity,并设置为默认的Activity.如何从一个Activity跳转到另一个Activity,还有就是详细分析Activity的生命周 ...

  4. Android 组件系列-----Activity的传值和回传值

    在这篇随笔里将讲解Activity的传值和回传值. 一.通过startActivity来进行Activity的传值 在Android中,如果我们要通过一个Activity来启动另一个Activity, ...

  5. Android 组件系列-----Activity初步

    在上篇博文讲解了Android的Activity这个组件的启动流程后,接下来我们就来看看我们的Activity与我们的布局文件的关系吧 我们先来看看一个最简单的布局文件的内容: <Relativ ...

  6. Android组件系列----Activity的生命周期

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  7. Fragment、Activity 保存状态

    Activity 保存状态1. void onCreate(Bundle savedInstanceState) 当Activity被第首次加载时执行.我们新启动一个程序的时候其主窗体的onCreat ...

  8. Android组件系列----当前Activity跳转到另一个Activity的详细过程

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  9. 第01讲 Android开发系列---Activity

    一.  Android系统版本及详细信息 最新数据  https://developer.android.com/about/dashboards/ 二.  Android项目初探 1.    使用a ...

随机推荐

  1. js取float型小数点后两位数的方法

    四舍五入以下处理结果会四舍五入:' var num =2.446242342; num = num.toFixed(2); // 输出结果为 2.45   不四舍五入以下处理结果不会四舍五入:第一种, ...

  2. ShellExecute的各种用法

    一.利用系统默认的邮件收发器发送电子邮件 Uses ..., ShellAPI; Var lpHwnd: HWND; lpOperation, lpFile, lpParameters, lpDire ...

  3. 【Linux】鸟哥的Linux私房菜基础学习篇整理(二)

    1. dumpe2fs [-bh] devicename:查询superblock信息.参数:-b:列出保留为坏道的部分:-h:列出superblock的数据,不会列出其他的区段内容. 2. df [ ...

  4. C&num;基础静态类的设计

  5. javascript中数组常用方法总结

    原文:javascript中数组常用方法总结 在javascript的基础编程中,数组是我们最常遇到的,那么数组的一些常用方法也是我们必须要掌握的,下面我们总结一下数组中常用的方法. toString ...

  6. js判断字符串中是否有数字和字母

    var p = /[0-9]/; var b = p.test(string);//true,说明有数字var p = /[a-z]/i; var b = p.test(string);//true, ...

  7. angular-utils-ui-breadcrumbs使用心得

    angular-utils-ui-breadcrumbs是一个用来自动生成面包屑导航栏的一个插件,需要依赖angular.UIRouter和bootstrap3.css.生成的界面截图如下,点击相应的 ...

  8. Matplotlib学习---用wordcloud画词云(Word Cloud)

    画词云首先需要安装wordcloud(生成词云)和jieba(中文分词). 先来说说wordcloud的安装吧,真是一波三折.首先用pip install wordcloud出现错误,说需要安装Vis ...

  9. bzoj 4621&colon; Tc605 动态规划

    题解: 一道比较简单的题目 想着想着就把题目记错了..想成了可以把某段区间覆盖为其中一个数 其实是比较简单的 每个点的贡献一定是一个区间(就跟zjoi2018那题一样) 然后问题就变成了给你n个区间让 ...

  10. 认识Thymeleaf:简单表达式和标签 基础信息

    转载:https://www.cnblogs.com/beyrl-blog/p/6633182.html 本文只适用于不会Java对HTML语言有基础的程序员们,是浏览了各大博客后收集整理,重新编辑的 ...