分类:C#、Android、VS2015;

创建日期:2016-02-21

一、简介

通过重写(也叫回调)对应的方法来管理Activity的生命周期,比如用户旋转屏幕时应用程序要能自动保存和恢复实例的状态,这对于开发一个健壮而又灵活的应用程序而言至关重要。

1、本节要点

一旦真正理解了Activity的生命周期,就可以轻松自如地通过C#代码去控制它了。这一节我们主要学习如何用Boundle存储简单类型的数据(比如int、double、string、bool、……等)。

当一个Activity停止或销毁时,系统会存储该Activity的状态,这个保存的状态称为实例状态。在Activity的生命周期中,Android提供了存储实例状态的三个选项:

  • 在叫做Boundle的“key/value”字典中保存元数据的值。
  • 创建一个自定义的类,用该类来维持复杂数据的状态,比如图像。
  • 不保存Activity的任何状态。即:以上两个事都不做。比如,从活动A转到活动B后,活动A原来的临时数据丢就丢了,反正活动B也用不到这些数据。

下面主要介绍前两个选项。

2、利用Bundle保存和恢复场景(实例)的状态

由于实例状态保存在称为Boundle的“key/value”字典中,因此,当创建一个Activty时,就可以在重写的OnCreate()方法中传递boundle来恢复原来的实例状态。

但是,不建议将图像等复杂数据保存在boundle中,这是因为图像不容易被串行化为“key/value”,这种情况下,应该将整个图像文件作为一个简单数据类型来看待(仅仅用字符串保存图像的文件名或URL,而不是保存完整的图像数据)。

Bundle为Activity提供了“保存”和“恢复”实例状态的两个方法:

  • OnSaveInstanceState – 当开始销毁Activity时Android将自动调用此方法。在这个方法中,可通过一系列【“键/值”对】来存储需要保存的项。
  • OnRestoreInstanceState – 当OnCreate()方法完成后Android将自动调用此方法,通过重写该方法,就可以恢复原来的状态。

注:不要对“状态”这个词迷惑了,它的本质含义举例来说就是:当活动A从可见变为不可见,然后再从不可见转为可见后,活动A原来的数据、选项、……等“状态”还需要在再次可见时重现吗,如果需要重现,就先在重写的OnSaveInstanceState()方法中保存这些数据、选项、……等场景,然后再在重写的OnRestoreInstanceState()方法中恢复这些场景。这样一来,不管Android系统内部怎样折腾,这些数据也不会丢了,仍然能在重新可见时重现原来的场景。

下图演示了如何使用这两个方法:

(1)OnSaveInstanceState()方法

当一个Activity被Paused或者Stopped时,如果这个Activity对象仍然被保留在内存中,那么就可以简单地通过Resume让这个Activity返回到前台。可是,当内存紧张时,系统可能会销毁这个Activity,这样程序就无法简单地通过Resume还原这个Activity了。如果用户还想返回到这个Activity,系统必须新建一个Activity让用户觉得原来的那个Activity还存在,可是如何还原到销毁前的状态呢?解决办法就是让系统在杀死那个Activity之前先调用OnSaveInstanceState()来保存原来的状态,这样就可以用它去恢复了。

具体办法是:在重写的OnCreate()方法或者重写的OnRestoreInstanceState()方法中从传递的Bundle中解析出保存的信息,并用它来恢复Activity原来的状态。

如果原来并没有储存状态信息,此时传入的Bundle将为null,比如第1次创建Activity时就是这种情况。

总之,将Activity状态完整地返回给用户的两种情况有:

(a)如果原来的Activity对象还保存在内存中,系统就直接通过Resumed还原原来的状态;

(b)如果原来的Activity对象已经不存在,系统就新建一个Activity,并检查是否保存了原来的状态,如果保存了就还原它,否则将新建的状态设置为null。

注意:系统不一定每次都在销毁这个Activity之前调用OnSaveInstanceState()方法 ,比如用户使用【Back】键关闭了这个Activity。在这种情况下,系统通常会在OnStop()方法之前或者在OnPause()之前调用OnSaveInstanceState(),而不是在销毁前去调用它。

还有一些情况,比如在layout文件夹下的布局文件中声明的控件,即使你不显式调用OnSaveInstanceState()方法,系统仍然会默认将其状态保存下来。但前提是你必须为想要保存其状态的控件(widget)提供一个唯一的ID。如果不给widget指定ID,系统是无法保存它的状态的。

另外,通过把android:saveEnabled 设置为"false",或者调用 SetSaveEnabled() 方法,也可以显式地阻止layout中的某个view保存状态。不过,通常不应该禁用保存,但是,假如你需要恢复activity UI的各个不同的状态,也许可以这么做。

尽管默认实现的 OnSaveInstanceState() 方法会保存activity UI的有用信息,但你仍然需要重写(override)它来存入更多的信息。 例如,你可能需要保存在activity生命周期中改变的成员变量值(比如恢复UI的值,默认情况下,这些UI状态的成员变量值是不会被恢复的)。

因为默认实现的 OnSaveInstanceState() 方法已经帮你保存了一些UI的状态,所以如果你为了保存更多的状态信息而重写此方法,那么在执行自己的代码之前应该确保先调用一次父类的 OnSaveInstanceState() 方法。同理,如果重写 OnRestoreInstanceState(),也应该调用一次父类的该方法,这样缺省的代码就能正常恢复view的状态了。

注意:因为 OnSaveInstanceState() 并不保证每次都会被调用,所以你应该只用它来记录activity的一些临时状态信息(UI的状态)——千万不要用它来保存那些需要长久保存的数据(比如那些需要存入数据库里的数据),而是应该在用户离开activity的时候在重写的 OnPause()方法中来保存这些永久性数据。

一个检测应用程序状态恢复能力的好办法就是旋转设备,使屏幕方向发生改变(在模拟器中可通过按<Ctrl>+<F11>让其旋转)。当屏幕的方向改变时,因为要换用符合实际屏幕参数的资源,所以系统会销毁并重建这个activity。正因如此,你的activity在被重建时能完整地恢复状态非常重要,因为用户可能会在使用应用程序时频繁地旋转屏幕。

本节的例子演示了如何在重写的OnSaveInstanceState()方法中保存状态数据。在这个例子中,用户每单击一次按钮,都会将count的值加1,并在TextView中将count的值显示出来。当改变配置状态时--比如用户旋转屏幕时--会丢失count的值(此时boundle将会为null),重而写该Activity的OnSaveInstanceState()方法即可保存count的值。这样一来,当设备旋转到一个新的状态时(比如按<Ctrl>+<F11>将模拟器从纵向变为横向),由于count的值已经保存到boundle中,因此可通过下面的办法重新获取这个值:

count = bundle.GetInt ("counter", -1);

注意:调用base.OnSaveInstanceState (outState)非常重要,这能确保始终存储视图的层次结构的所有原始状态。

(2)OnRestoreInstanceState()方法

设备的某些配置可能会在运行时发生变化(比如屏幕方向、键盘可用性以及国家语言等状态发生了变化)。当发生这些变化时,Android会重建这个运行中的activity,即:系统会先调用OnDestroy() ,再调用OnCreate()。这种设计有助于应用程序适用新的参数配置,措施就是通过把你预置的可替换资源(比如对应各种屏幕方向和尺寸的layout)自动重新装载到应用程序中。

如果你采取了适当的设计,让activity能够正确地处理这些因为屏幕方向而引起的重启,并能如上面所述的那样恢复activity的状态,那么你的应用程序将对生命周期中其它的意外事件更具适应能力。

处理这类重启的最佳方式,就是在重写的OnSaveInstanceState()方法中保存状态,在重写的OnRestoreInstanceState()或者OnCreate()中恢复状态。

这个例子是通过在重写的OnCreate()方法恢复状态的。

实际上,在许多情况下,并不需要总是重写OnRestoreInstanceState()方法,因为大多数活动都可以在重写的OnCreate()方法中直接恢复原来的状态。

二、示例2—状态保存和恢复

此示例演示了如何保存和恢复用户旋转屏幕前后的状态。

1、运行截图

单击按钮3次的截图如下:

按【Ctrl】+【F11】后的截图如下:

再次按【Ctrl】+【F11】再次切换为纵向放置。

2、实现步骤

(1)添加ch1102_Layout.axml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="你单击了按钮 0 次"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textViewCount"
android:layout_margin="20dp"
android:gravity="center_horizontal" />
<Button
android:id="@+id/btn1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="请多次单击" />
<TextView
android:text="提示:【Ctrl】+【F11】用于控制模拟器的屏幕【纵向/横向】转换,多次按它观察屏幕旋转后单击按钮的次数显示的情况。"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView2"
android:layout_margin="20dp" />
</LinearLayout>

(2)添加ch1102Activity.cs文件

using Android.App;
using Android.OS;
using Android.Widget; namespace MyDemos.SrcDemos
{
[Activity(Label = "【例11-2】状态保存与恢复")]
public class ch1102Activity : Activity
{
private int count = 0;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ch1102_Layout);
var txtCount = FindViewById<TextView>(Resource.Id.textViewCount);
if (savedInstanceState != null)
{
count = savedInstanceState.GetInt("counter", 0);
txtCount.Text = $"你单击了按钮 {count} 次";
}
var btn1 = FindViewById<Button>(Resource.Id.btn1);
btn1.Click += (s, e) =>
{
count++;
txtCount.Text = $"你单击了按钮 {count} 次";
};
} protected override void OnSaveInstanceState(Bundle outState)
{
outState.PutInt("counter", count);
base.OnSaveInstanceState(outState);
}
}
}

【Android】11.2 通过重写对应的方法保存和恢复实例的状态的更多相关文章

  1. 【转】android笔记--保存和恢复activity的状态数据

    一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会 ...

  2. Android 保存和恢复activity的状态数据

    一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会 ...

  3. android 19 activity纵横屏切换的数据保存与恢复

    Bundle类:竖屏的activity换到横屏的activity的时候,会把竖屏的activity杀掉横屏的activity创建,竖屏的activity会有一些计算结果,可以用数据存起来,存到内存里面 ...

  4. Android Fragment使用(三) Activity, Fragment, WebView的状态保存和恢复

    Android中的状态保存和恢复 Android中的状态保存和恢复, 包括Activity和Fragment以及其中View的状态处理. Activity的状态除了其中的View和Fragment的状 ...

  5. Android之Activity状态的保存和恢复

    系统在某些情况下会调用onSaveInstanceState()和onRestoreInstanceState() 这两个方法来保存和恢复Activity的状态. 一句话:Activity在" ...

  6. Android 自己定义View须要重写ondraw()等方法

    Android  自己定义View须要重写ondraw()等方法.这篇博客给大家说说自己定义View的写法,须要我们继承View,然后重写一些 方法,方法多多,看你须要什么方法 首先写一个自己定义的V ...

  7. Android View各种尺寸位置相关的方法探究

    Android View各种尺寸位置相关的方法探究 本来想做一个View间的碰撞检测之类的. 动手做了才发现不是想象的那么简单. 首先,写好了碰撞检测的工具类如下: package com.mengd ...

  8. Android 使用 DownloadManager 管理系统下载任务的方法,android管理系统

    从Android 2.3(API level 9)开始Android用系统服务(Service)的方式提供了Download Manager来优化处理长时间的下载操作.Download Manager ...

  9. Android中点击隐藏软键盘最佳方法——Android开发之路4

    Android中点击隐藏软键盘最佳方法 实现功能:点击EditText,软键盘出现并且不会隐藏,点击或者触摸EditText以外的其他任何区域,软键盘被隐藏: 1.重写dispatchTouchEve ...

随机推荐

  1. 怎样查看class文件的jdk版本号

    1.事先编译好一个class文件.如:TestVersion.class 2.使用UltraEdit或Editplus打开class文件,我这里使用的editplus,如图: 3.打开时Encodin ...

  2. 【Maven】IKAnalyzer 在Maven Repository不存在

    1.在mvnrepository里面找IKAnalyzer,这个中文分词包,一直没有找到,找到github,发现是一个国人写的. http://mvnrepository.com/search?q=I ...

  3. jqGrid删除多行数据问题

    var consoleDlg = $("#delcostListDlg"); var selectedRowIds = $("#costList").jqGri ...

  4. JQuery URL的GET参数值获取方法

    // jQuery url get parameters function [获取URL的GET参数值] // <code> // var GET = $.urlGet(); //获取UR ...

  5. Flash:DisplayObject的transform/matrix的潜规则、小bug

    AS3中,使用DisplayObject的transform/matrix,需要先clone出来,再变换,再赋值回去,这样才会对DisplayObject产生影响,不能直接对原Matrix操作.   ...

  6. plsql 存储过程 测试

      plsql 存储过程 测试 CreationTime--2018年8月14日09点54分 Author:Marydon 1.找到要运行的存储过程-->选中-->右键-->测试 2 ...

  7. TOMCAT清理

      CreateTime--2017年7月10日08:54:00Author:Marydon 如何清理TOMCAT 方式一:通过tomcat的安装目录进行清理 找到TOMCAT的根目录,如图: 实质: ...

  8. 〖Linux〗gvim使用alt+1,2,3..进行标签页切换

    gvim ~/.gvimrc,往里边添加: """"""""""""" ...

  9. python之函数用法any()

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法any() #any() #说明:如果iterable的任何元素不为0.''.Fals ...

  10. log4j 日志 配置 学习

    1.用的flume-log4j  avrosource的整合 2.学习如何指定类打印日志 #log4j.rootLogger=INFO,flume 这个是将全部的日志会打印出来 log4j.logge ...