Activity数据的缓存

看如下场景:
  
  有A、B两个Activity,当从A进入到B中,如果系统内存不够,那么这时候A可能会被系统回收掉,这时候,我们再按back键,那么,执行的就不是A的onRestart()方法,而是onCreate()了,A被重新创建了一次,那么A中的临时数据可能就丢失了。
  
  这时候如果要保存这些数据怎么办?当然是有办法的。Activity中有一个onSaveInstanceState()就是用来干这活的。先来看看它的代码实现:
  

protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

  我们看到,它有一个Bundle参数,通过outState.putString(key,value)、outState.putInt(key,value)等不同的方法将临时数据保存下来。

  那么这些数据保存到哪里去了,又是什么时候调用?既然它能够起到缓存的作用,那么在Activity启动,也就是onCreate的时候,就肯定会去调用这些数据的是吗,我们来看看OnCreate()方法的实现:

@MainThread
    @CallSuper
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
        if (mLastNonConfigurationInstances != null) {
            mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
        }
        if (mActivityInfo.parentActivityName != null) {
            if (mActionBar == null) {
                mEnableDefaultActionBarUp = true;
            } else {
                mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
            }
        }
        //这里是为了保存第一次的时候savedInstanceState 为空,由这里我们可以看到是取了值的。
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate();
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        if (mVoiceInteractor != null) {
            mVoiceInteractor.attachActivity(this);
        }
        mCalled = true;
    }

由上面我们就知道了它的运行机制了,那么我们自己该如何使用它呢,我写一段简短的代码大家看一下:

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("myStringData","11111111");
        outState.putInt("myIntData",1);
    }

OK,在onCreate中取值。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //第一次创建,判空。
        if( savedInstanceState != null ){
            String myStringData = savedInstanceState.getString("myStringData");
            int myIntData = savedInstanceState.getInt("myIntData");
            ...
        }
    }

  知道了运行原理了,也知道该如何用了,下面我们来看看我们应该在什么场景下用它。
当某个activity很“容易”被系统销毁时,该onSaveInstanceState()就会被执行,除非该Activity是主动被用户销毁的,例如按back键时。
那么?什么是“容易”呢?有以下几种情况:
  1:当用户按下HOME键时;显而易见,系统不知道你按下HOME键后要运行多少程序,而你按下HOME键前的Activity有可能会被系统回收掉,所以这时候必定会执行。
  2:长按HOME键,运行其他程序,这个和第一情况类似。
  3:按下电源键(关闭屏幕)时;这个不解释。
  4:从Activity中启动一个新的Activity时,就是开篇的那种场景。
  5:屏幕方向切换时,例如,从竖屏切换到横屏(如果不指定configchange属性),在切换前,系统会销毁Activity A,切换之后又会重新自动的创建Activity A,所以onSaveInstanceState()一定会被执行。
总而言之,onSaveInstanceState()的调用遵循一个重要原则,既系统“未经你许可”时销毁了你的Activity,则onSaveInstanceState()会被系统调用,这是系统的责任,因为它必须提供一个机会让你保存数据。

需要注意的几点:
  1:布局中的每一个View默认实现了onSaveInstanceState()方法,这样的话,这个UI的任何改变都会自动的存储和在activity重新创建的时候自动的恢复。但是这种情况只有在你为这个UI提供了唯一的ID之后才起作用,如果没有提供ID,将不会存储它的状态。

  2:由于默认的onSaveInstanceState()方法的实现帮助UI存储它的状态,所以如果你需要覆盖这个方法去存储额外的状态信息时,你应该在执行任何代码之前都调用父类的onSaveInstanceState()方法(super.onSaveInstanceState())。既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要。

  3:由于onSaveInstanceState()方法调用的不确定性,你应该只使用这个方法去记录activity的瞬间状态(UI的状态)。不应该用这个方法去存储持久化数据。当用户离开这个activity的时候应该在onPause()方法中存储持久化数据(例如应该被存储到数据库中的数据)。

  4:onSaveInstanceState()如果被调用,这个方法会在onStop()前被触发,但系统并不保证是否在onPause()之前或者之后触发。

  另外,还有一个方法onRestoreInstanceState(Bundle outState)需要注意,两个方法不一定是成对出现的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行。另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。
还有onRestoreInstanceState在onstart之后执行。至于这两个函数的使用,给出示范代码(留意自定义代码在调用super的前或后):

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putBoolean("myBoolean", true);
        savedInstanceState.putDouble("myDouble", 1.0f);
        savedInstanceState.putInt("myInt", 1);
        savedInstanceState.putString("myString", "11111111");
        super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        boolean myBoolean = savedInstanceState.getBoolean("myBoolean");
        double myDouble = savedInstanceState.getDouble("myDouble");
        int myInt = savedInstanceState.getInt("myInt");
        String myString = savedInstanceState.getString("myString");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值