Android中突发情况Activity数据的保存和恢复

写在前面:
在我们的APP使用的过程中,总有可能出现各种手滑、被压在后台、甚至突然被杀死的情况。所以对APP中一些临时数据或关键持久型数据,就需要我们使用正确的方式进行保存或恢复。

突发情况都有哪些?

因为本文讨论的是当一些突发情况的出现时,对数据的保存和恢复。所以现在总结一下突发情况应该都有哪些?

      • 点击back键

      • 点击锁屏键

      • 点击home键

      • 其他APP进入前台

      • 启动了另一个Activity

      • 屏幕方向旋转

      • APP被Kill

当这些突发情况发生的时候,有哪些关键的方法会被调用呢?

写了一个简单的demo,我用上述的突发情况进行测试,代码中我重写了所有Activity的生命周期方法onSaveInstanceState方法,并打印对应的log在控制台,下面是demo图:

这里就不贴出测试的过程了,直接来告诉大家测试的结果吧:

当我的APP处在前台,能与用户交互的情况下,出现上述的突发事件时,只有点击back键onSaveInstanceState方法不会调用。其余的情况下, 该方法一律都会调用,这又是为什么呢?并且onPause方法是必然会调用的,这又给我们保存数据提供了怎样的思路呢?

onSaveInstanceState

好吧,相信当你看到本文标题的时候,你就应该想到了这个方法。因为当我们学习Android基础知识时,用onSaveInstanceState方法进行数据恢复是你必然学到过的。所以前面我营造出的一些悬念看似是失败了,不过对于onSaveInstanceState你理应知道更多知识:

      1. 何时调用:
> Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother
calling it when the instance is actually being destroyed by a user
action (such as pressing the BACK key)

找到了以上一段话,翻译过来就是当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。

结合我们以上的例子,其实都在说明一个词,就是**被动**。当Activity并不是由我主动点击back键而丧失焦点时,onSaveInstanceState方法就一定会调用。就例如我上述列举的那些除了点击back键的“**突发情况**”。
      1. 何地调用:

        在我写的这个demo中,onSaveInstanceState的调用是处于onPauseonStop之间的,(下面关于Activity的生命周期方法,会讲解一些值得大家注意的),我查阅了一下资料,能保证的是onSaveInstanceState方法会在onStop之前调用,但是是否在onPause之前就不一定了。

结论: google工程师们对onSaveInstanceState如此设计就是让其完成对一些临时的、非永久数据存储并进行恢复。什么样的数据属于临时数据呢?举个例子,比如EditText中输入的内容,CheckBox是否勾选,ScrollView的滑动位置,目前视频的播放位置等等。

当我还没有自学Android时,玩着一些APP就会产生一个疑问,比如我在一个输入框中输入了大量文字没有提交或者保存。此时来了一个电话,如果退回的时候,输入框里面的文字消失了,那我可能会砸了电话,所以这个保存数据的操作,是Android开发者做的吗?

然而是不需要的,因为Android的View本身自己就实现了onSaveInstanceState方法,这些控件自己就具有保存临时数据和恢复临时数据的能力。

例如TextView中的部分源码:

其他View控件都有相似的实现原理。值得一提的是,只有当你给这个wiget在xml中指定id时,它才具有保存数据并且恢复的能力,并且不同的wiget还不能共用这个id,否则会出现数据覆盖的情况。具体的源码有兴趣大家可以自己去看,这里因为篇幅的原因不再贴出,关于onSaveInstanceState我们先说这些,赶紧看看使用姿势。

onSaveInstanceState的使用姿势

比如我们要保存当前视频的播放进度,这个显然控件没有帮我们实现onSaveInstanceState,所以就只能靠自己了,代码如下所示。


当在onCreate取出临时数据时,记得加一个非空判断

看到这里,也许你认为本文该就此结束了,不过在回过头看看,我们刚才一直强调的是临时数据,毕竟onSaveInstanceState本身就是为临时数据服务的,但是一些永久性质的数据,比如插入数据库的操作,我们应该在什么方法中对其进行保存呢?

onPause

在介绍onPause方法之前,还是想聊聊Activity的生命周期方法,相信大家对它应该有了初步的了解,不过在相应的生命周期方法中,我们应该做什么操作呢?推荐给大家一篇文章,我觉得不错。

Activity生命周期详解

关于onPause,我找到了一下关于它的特性:

onPause(), onStop(), onDestroy() are “killable after” lifecycle methods. This indicates whether or not the system can kill the process hosting the activity at any time after the method returns, without executing another line of the activity’s code. Because onPause() is the first of the three, once the activity is created, onPause() is the last method that’s guaranteed to be called before the process can be killed—if the system must recover memory in an emergency, then onStop() and onDestroy() might not be called. Therefore, you should use onPause() to write crucial persistent data (such as user edits) to storage. However, you should be selective about what information must be retained during onPause(), because any blocking procedures in this method block the transition to the next activity and slow the user experience.

翻译过来就是:无论出现怎样的情况,比如程序突然死亡了,能保证的就是onPause方法是一定会调用的,而onStop和onDestory方法并不一定,所以这个特性使得onPause是持久化相关数据的最后的可靠时机。当然onPause方法不能做大量的操作,这会影响下一个Activity入栈。

刚才我们的测试结果还说明了一个道理,onSaveInstanceState并不是百分百调用的(比如点击了back键),显然一些永久性的数据,我们并不能在此中保存。

关于本文的结论就显而易见了,我们来一句话总结一下:

临时数据使用onSaveInstanceState保存恢复,永久性数据使用onPause方法保存。

Android中突发情况Activity数据的保存和恢复的更多相关文章

  1. Android中解析XML格式数据的方法

    XML介绍:Extensible Markup Language,即可扩展标记语言 一.概述 Android中解析XML格式数据大致有三种方法: SAX DOM PULL 二.详解 2.1 SAX S ...

  2. activity状态的保存和恢复

    activity状态的保存和恢复 一.简介 1.保存activity状态 * 保存activity状态,onSaveInstanceState这个方法会自动保存有ID的组件的状态 * 没有ID的组件或 ...

  3. Android开发中Activity状态的保存与恢复

    当置于后台的Activity因内存紧张被系统自动回收的时候,再次启动它的话他会重新调用onCretae()从而丢失了之前置于后台前的状态. 这时候就要重写Activity的两个方法来保存和恢复状态,具 ...

  4. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  5. Android中Service和Activity之间的通信

    启动Service并传递数据进去: Android中通过Intent来启动服务会传递一个Intent过去. 可以在Intent中通过putExtra()携带数据 Intent startIntent ...

  6. Android中的5种数据存储方式

    本文转自  http://hi.baidu.com/maguowei/blog/item/7aca46c25574a33ae5dd3ba4.htmlAndroid数据存储Android提供了5种方式存 ...

  7. Android 中的MVC与数据流动

    今天看了一个Android的Training生命周期转换的例子,顿觉得他的设计非常巧妙,我的分析如下: 1.在com.example.android.lifecycle包中有: 3个正常的全屏acti ...

  8. Xamarin Android 中Acitvity如何传递数据

    在xamarin android的开发中,activity传递数据非常常见,下面我也来记一下在android中activity之间传递数据的几种方式, Xamarin Android中Activity ...

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

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

随机推荐

  1. oracle中的cluster表

    大家对通常oracle中的cluster的理解是不准确的,经常和sql server中的cluster index混淆.Cluster是存储一组table的一种方法,这些table共享同一数据块中的某 ...

  2. 创建一个Windows窗体

    20140702加: WS_OVERLAPPEDWINDOW这个属性如果写成WS_OVERLAPPED,则窗口没有最大最小按钮以及左边的系统的菜单. vs2010下的代码提示快捷键:CTRL + J ...

  3. ICTCLAS50中文分词软件“Init ICTCLAS failed!”问题

    if (!ICTCLAS_Init(Server.MapPath("ICTCLAS50")))            {               Response.Write( ...

  4. 查看ubuntu文件目录的大小和文件夹包含的文件数 zT

    查看ubuntu文件目录的大小和文件夹包含的文件数 查看linux文件目录的大小和文件夹包含的文件数 统计总数大小 du -sh xmldb/ du -sm * | sort -n //统计当前目录大 ...

  5. python实现简单随机模拟——抛呀抛硬币

    还是在上次提到的数据之魅那本书,看到模拟这章,有个python模拟脚本,但书上不全,就自己简单写了下. 流程:在不同的平衡参数p(为0.5时为均匀的)下,模拟60次实验,每次投硬币8次,统计正面朝上的 ...

  6. ++index 与 index++

    摘自:C++标准程序库

  7. IndexOf() LastIndexOf() Contains() StartsWith() EndsWith()方法比较

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  8. 锋利的jQuery之事件

    jQuery中的事件和动画 JavaScript和HTML之间的交互是通过用户和浏览器操作页面时引发的事件来处理的.当文档或者它的某些元素发生某些变化或操作时,浏览器会自动生成一个事件.例如:当浏览器 ...

  9. 【转】C++析构函数为什么要为虚函数

    注:本文内容来源于zhice163博文,感谢作者的整理. 1.为什么基类的析构函数是虚函数? 在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生. 下面转自网络:源地址  ...

  10. Link Aggregation and LACP with Open vSwitch

    In this post, I’m going to show you how to use link aggregation (via the Link Aggregation Control Pr ...