Activity数据保存探索

在开发中发现一个问题:当一个我通过Intent开启一个前面已经打开的activty的界面时,

新打开的activity的状态会丢失。当时,当我直接按home减将acitvity置于后台,然后重新打开这个activity的时候,发现此时的activity的状态是退出之前的状态。但是,我现在我想达到的目的是,不管是以什么方式打开这个活动,我都想要他恢复到之前的acitvity状态,而不是新开一个新的activity。于是针对这现象,我寻求解决方案。

利用onSaveInstanceState和onRestoreInstanceState

在发现这个问题之后,我的第一感觉就是利用activity中的onRestoreInstanceState方法在打开新的activity时将保存的数据读取并写入到新的activity中,实现的原理就是我之前说的按下home键重新打开activity能恢复到原来的activity状态的原理。在这里我将展开讲解activity中数据的保存机制。

activity的生命周期

要想完全理解activity中的储存机制,就必须对activity的生命周期非常熟悉,在这里我就简单介绍一下acttivity的生命周期。这里直接给出一张官方的activity生命周期图:

如果对activity的生命周期还是不太了解,可以参考我后面代码里面对每个activity周期的方法的注释。这里就不做过多的解释。

### acitvity中的数据储存机制

当一个activity被paused或者stopped时,activity的状态可以被保存。 的确如此,因为 Activity 对象在paused或者stopped时仍然被保留在内存之中——它所有的成员信息和当前状态都仍然存活。 这样用户在activity里所作的改动全都还保存着,所以当activity返回到前台时(当它“resume“),那些改动仍然有效。
不过,如果系统是为了回收内存而销毁activity,则这个 Activity 对象就会被销毁,这样系统就无法简单地resume一下就能还原完整状态的activity。 如果用户要返回到这个activity的话,系统必须重新创建这个Activity 对象。可是用户并不知道系统是先销毁activity再重新创建了它的,所以,他很可能希望activity完全保持原样。 这种情况下,你可以保证activity状态的相关重要信息都由另一个回调方法保存下来了,此方法让你能保存activity状态的相关信息: onSaveInstanceState()。
在activity变得很容易被销毁之前,系统会调用 onSaveInstanceState()方法。 调用时系统会传入一个Bundle对象, 你可以利用 putString() 之类的方法,以键值对的方式来把activity状态信息保存到该Bundle对象中。 然后,如果系统杀掉了你的application进程并且用户又返回到你的activity,系统就会重建activity并将这个 Bundle 传入onCreate() 和onRestoreInstanceState() 中,你就可以从 Bundle 中解析出已保存信息并恢复activity状态。如果没有储存状态信息,那么传入的 Bundle 将为null(当activity第一次被创建时就是如此)

这里在给出官方的图片来说明activity状态的存储

或许这个能更加直观的表现 onSaveInstanceState()和onRestoreInstanceState()的调用

但是注意,这里的activity数据保存的情况只能是activity被==意外==的销毁了,而被认为是用户主动销毁的activity则不会保存数据则不会调用这些保存数据的方法。

那么哪些是==意外==销毁activity的情况?

* 用户按下HOME键的时候

* 长安HOME键,运行其他程序

* 按下电源键(关闭屏幕显示)

* 从一个activity A中启动一个新的activity

* 屏幕方向发生改变

所以在上述情况下,activity会默认调用onSaveInstanceState()来保存数据,至于调用顺序,请参照前面的图片。、

讲到这里,就不得不说说重写onSaveInstanceState()方法了。

如果需要保存额外的数据时, 就需要覆写onSaveInstanceState()方法。大家需要注意的是:onSaveInstanceState()方法只适合保存瞬态数据, 比如UI控件的状态, 成员变量的值等,而不应该用来保存持久化数据,持久化数据应该当用户离开当前的 activity时,在 onPause() 中保存(比如将数据保存到数据库或文件中)。说到这里,还要说一点的就是在onPause()中不适合用来保存比较费时的数据,所以这点要理解。

由于onSaveInstanceState()方法方法不一定会被调用, 因此不适合在该方法中保存持久化数据, 例如向数据库中插入记录等. 保存持久化数据的操作应该放在onPause()中。若是永久性值,则在onPause()中保存;若大量,则另开线程吧,别阻塞UI线程。

讲到这里,好像有点明了,那么只要我们在activity中显示的调用onSaveInstanceState(),不久可以很好的解决这个问题么,于是我写了如下的代码,这里是MainActivity的内容。

package com.create.activitydata;

import android.content.Intent;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;

/**
 * 测试保存Activity中的数据
 */
public class MainActivity extends AppCompatActivity {
    private EditText editText;
    private CheckBox checkBox;
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText)findViewById(R.id.text);
        checkBox = (CheckBox)findViewById(R.id.check);

    }

    /**
     * activity被停止后、又再次被启动之前调用。
     下一个回调方法总是onStart()
     */
    @Override
    protected void onRestart() {
        //这里可以手动添加读取Activity的UI状态代码
        super.onRestart();

    }

    /**
     * activity要显示给用户之前调用。
     *如果activity进入前台,则下一个回调方法是onResume();
     *如果进入隐藏状态,则下一个回调方法是onStop()。
     */
    @Override
    protected void onStart() {
        super.onStart();
    }

    /**
     * activity开始与用户交互之前调用。这时activity是在activity栈的顶端,用户可以向其中输入。
     *下一个回调方法总是onPause()。
     */
    @Override
    protected void onResume() {
        super.onResume();
    }

    /**
     * 当系统准备启动另一个正在恢复的activity时调用。这个方法通常用于把未保
     * 存的改动提交为永久数据、停止动画播放、以及其它可能消耗CPU的工作等等。 它应该非常迅速
     * 地完成工作,因为下一个activity在本方法返回前是不会被恢复运行的。
     * 如果activity返回前台,则下一个回调方法是onResume();如果进入用户不可见状态,则下一个是onStop()
     */
    @Override
    protected void onPause() {
        super.onPause();
        //在这里可以添加比较耗时,需要长久保存的数据。
    }

    /**
     * 当activity不再对用户可见时调用。原因可能是它即将被销毁、或者其它activity(已有或新建的)
     * 被恢复运行并要覆盖本activity。
     *如果activity还会回来与用户交互,则下一个回调方法是onRestart();如果这个activity即将消失,
     *则下一个回调方法是onDestroy()
     */
    @Override
    protected void onStop() {
        //在这里添加保存Activity状态的代码
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    /**
     * 读取数据
     * 读取和储存Activity状态的两个方法并不在Activity生命周期中
     * 但在Activity意外停止时系统会调用缺省的方法保存当前状态,并在
     * 下次打开Activity是调用onSaveInstanceState以恢复到原来的状态
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.e(TAG,"onRestoreInstanceState");
    }

    /**
     * 保存数据
     * @param outState
     * @param outPersistentState
     */
    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        Log.e(TAG,"onSaveInstanceState");

    }

    public void toNext(View view){
        Intent intent = new Intent(MainActivity.this,NextActivity.class);
        startActivity(intent);
    }

}

但是在这里我想说,我试了很久也没能显示的调用onSaveInstanceState()这些方法,对activity里面的源代码并没有多大的理解,于是我放弃了用这种方法去恢复activity的状态

(ps,对了,在这里加一句,只有加了id的控件调用onSaveInstanceState()时才能正常保存,否则也会失败,至于如何使这个方法失效,可以通过把android:saveEnabled 设置为”false”,或者调用 setSaveEnabled() 方法)

利用activity的启动方式

在上面的方法失败之后,我又需求别人的帮助。给出的思路就是,当利用Intent开启一个已经被开启过的activity时,没必要再重新new一个activity了,而是直接打开之前的那么activity。想到这,焕然大悟:这个我可以直接利用activity的启动方式来时事当前的activity一直处于栈顶,当开启他的时候,直接打开它而不是new一个activity。这样就完美的解决了我的问题。仅仅一行代码。

首先activity的启动模式只有四种:

* standard

standard是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用 这种启动模式。在 standard模式(即默认情 况)下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用 standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建 该活动的一个新的实例。

* singleTop

当活动的启动模式 指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用 它,不会再创建新的活动实例。

* singleTask

使用 singleTop模式可以很好地解决重复创建栈顶活动的问题,但是正如你在上一节所 看到的,如果该活动并没有处于栈顶的位置,还是可能会创建多个活动实例的。那么有没有 什么办法可以让某个活动在整个应用程序的上下文中只存在一个实例呢?这就要借助 singleTask模式来实现了。当活动的启动模式指定为 singleTask,每次启动该活动时系统首先 会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这 个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

* singleInstance

singleInstance模式的活动会启用一 个新的返回栈来管理这个活动(其实如果 singleTask模式指定了不同的 taskAffinity,也会启 动一个新的返回栈),在这种模式下会有一个单独的返回栈来管理这个活 动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实 例的问题。

留个漂亮的尾巴~

时间: 2024-11-10 10:26:33

Activity数据保存探索的相关文章

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

Android中突发情况Activity数据的保存和恢复 写在前面:在我们的APP使用的过程中,总有可能出现各种手滑.被压在后台.甚至突然被杀死的情况.所以对APP中一些临时数据或关键持久型数据,就需要我们使用正确的方式进行保存或恢复. 突发情况都有哪些? 因为本文讨论的是当一些突发情况的出现时,对数据的保存和恢复.所以现在总结一下突发情况应该都有哪些? 点击back键 点击锁屏键 点击home键 其他APP进入前台 启动了另一个Activity 屏幕方向旋转 APP被Kill 当这些突发情况发

安卓第二天笔记-数据保存

安卓第二天笔记--数据保存 1.保存数据私有文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent&

Android 数据保存

Android数据保存方法 android数据保存主要保存以下三种: 1.共享参数文件中保存简单的键值对数据: 2.保存任意的文件数据到Android的文件系统中: 3.使用SQLite数据库管理 保存键值集 通过使用SharePreferences API来保存简单的键值对数据. 共享参数文件的获取或创建: 可以通过以下两种方法来获取: getSharedPreferences()  该方法需要提供一个共享参数文件的名称标识,该方法可以在任意Context中调用 getPreferences(

activity状态保存的bundl对象存放位置的思考

我们知道,当activity被异常终止时,可以把一些信息保存到bundle对象中,在下次启动时恢复. 那么,这个bundle对象是保存在哪里的呢? 这种状态保存的方法针对的是activity而不是进程,那么我们就可以猜测,这个对象是保存在内存中的,而不是存储设备上. 如果想对于进程进行数据保存等,应该使用外部存储来保存,在初始化的时候读取并恢复.

活动被回收和数据保存

一.问题由来:如果一个Activity处于停止状态,那么在内存紧张的时候,该活动就有可能被回收,这个时候,回退到该Activity,将会启动onCreate,之前在该Activity做的数据修改,将会丢失. 二.系统在回收活动时,会调用onSaveInstanceState方法,重载该方法,保存数据,在onCreate中再取出数据 // 保存数据@Overrideprotected void onSaveInstanceState(Bundle outState) { super.onSaveI

将数据保存的SDCard

将数据保存的SDCard前需要先声明权限 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.filesavetosdcard" android:versionCode="1" andr

内存卡的数据保存与读取

,内存卡 2.1数据保存 File file=new File(Environment.getExternalStorageDirectory(), name); try { FileOutputStream   fos=new FileOutputStream(file); fos.write(content.getBytes()); fos.close(); Toast.makeText(getApplicationContext(), "保存成功", 200).show(); }

Android数据保存之文件保存

前言: 上一篇文章写了在Android中利用SharedPreferences保存数据,SharedPreferences在保存数据的时候主要是保存一些应用程序的设置信息或者少量的用户信息,而且是以key-value形式保存的String类的信息,比較有局限性. 比方你须要保存从网络获取的图片到本地作为缓存数据,而且数量比較大.SharedPreferences就不能满足你的需求了,这个时候就要用到基本上全部平台都会用到的文件保存. Android中以文件形式把数据保存到磁盘上与其它平台基本上都

Hibernate数据保存操作方法的原理对比

Interface Session All Superinterfaces: Serializable All Known Subinterfaces: EventSource, Session All Known Implementing Classes: SessionImpl public interface Session  extends Serializable Java应用程序与Hibernate之间的主要运行时接口.它是抽象了持久化服务概念的核心抽象API类. Session的生