分类: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. Codeforces#86D Powerful array(分块暴力)

    Description An array of positive integers a1, a2, ..., an is given. Let us consider its arbitrary su ...

  2. (转)解决 bitmap size exceeds VM budget (Out Of Memory 内存溢出)的问题

    在做图片处理的时候最常遇到的问题估计就是Out Of Memory (内存溢出)了 网上对这种问题的解决方案很多,原来无非就是压缩图片大小 本不该重复造轮子,但实际中却遇见了问题,写出来希望后来者能引 ...

  3. 总结js(1)

    已经一个月没敲代码了,工作难找,挺烦. 先总结一下javascript吧. 1.js概述 2.语法结构 3.类型.值和变量 4.表达式和运算符 5.语句 6.对象 7.数组 8.函数 9.类和模块 1 ...

  4. innodb_file_per_table

    MySQL InnoDB引擎 默认会将所有的数据库InnoDB引擎的表数据存储在一个共享空间中:ibdata1,当增删数据库的时候,ibdata1文件不会自动收缩,单个数据库的备份也将成为问题.通常只 ...

  5. ftpclient 编码备忘

    if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {// ...

  6. 短信api接口

    1.需要用到的结构 typedef struct _SM_PARAM { char SCA[16];//+8613552678753// 短消息服务中心号码(SMSC地址) char TPA[16]; ...

  7. RAM调优之日志分析

    D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats> ...

  8. 〖Windows〗Linux的Qt程序源码转换至Windows平台运行,编码的解决

    在中国大陆,Windows默认的编码是gb2312,而Linux是UTF8: 多数情况下,把Linux上的程序转换至Windows上运行需要进行编码转换才能正常显示: 而其实大可以不必的,同样,文件使 ...

  9. Android 华为U8818真机调试 无法打印Logcat

    摘抄至:http://blog.csdn.net/studyalllife/article/details/8558258 在我们使用真机进行Android应用调试时,无法获得调试信息,错误提演示样例 ...

  10. 转载:substr() mb_substr() mb_subcut区别与联系

    substr() $rest = substr("abcdef", 1); //bcdef $rest = substr("abcdef", 1,5); //b ...