现在的位置: 首页 > 综合 > 正文

Android BaseSavedState 以及 Activity onSaveInstanceState 和 onRestoreInstanceState 方法使用注意事项

2014年11月11日 ⁄ 综合 ⁄ 共 8006字 ⁄ 字号 评论关闭


下面的代码来自View这个类,是一个关于状态保存的类,我们浏览器用与崩溃恢复,很有用的哦,我还看到过同事用来做View的状态保存,反正很强大的说~

/**
     * Base class for derived classes that want to save and restore their own
     * state in {@link android.view.View#onSaveInstanceState()}.
     */
    public static class BaseSavedState extends AbsSavedState {
        /**
         * Constructor used when reading from a parcel. Reads the state of the superclass.
         *
         * @param source
         */
        public BaseSavedState(Parcel source) {
            super(source);
        }

        /**
         * Constructor called by derived classes when creating their SavedState objects
         *
         * @param superState The state of the superclass of this view
         */
        public BaseSavedState(Parcelable superState) {
            super(superState);
        }

        public static final Parcelable.Creator<BaseSavedState> CREATOR =
                new Parcelable.Creator<BaseSavedState>() {
            public BaseSavedState createFromParcel(Parcel in) {
                return new BaseSavedState(in);
            }

            public BaseSavedState[] newArray(int size) {
                return new BaseSavedState[size];
            }
        };
    }

相关的有Activity的onSaveInstanceState,onRestoreInstanceState:

    /**
     * Called to retrieve per-instance state from an activity before being killed
     * so that the state can be restored in {@link #onCreate} or
     * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
     * will be passed to both).
     *
     * <p>This method is called before an activity may be killed so that when it
     * comes back some time in the future it can restore its state.  For example,
     * if activity B is launched in front of activity A, and at some point activity
     * A is killed to reclaim resources, activity A will have a chance to save the
     * current state of its user interface via this method so that when the user
     * returns to activity A, the state of the user interface can be restored
     * via {@link #onCreate} or {@link #onRestoreInstanceState}.
     *
     * <p>Do not confuse this method with activity lifecycle callbacks such as
     * {@link #onPause}, which is always called when an activity is being placed
     * in the background or on its way to destruction, or {@link #onStop} which
     * is called before destruction.  One example of when {@link #onPause} and
     * {@link #onStop} is called and not this method is when a user navigates back
     * from activity B to activity A: there is no need to call {@link #onSaveInstanceState}
     * on B because that particular instance will never be restored, so the
     * system avoids calling it.  An example when {@link #onPause} is called and
     * not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:
     * the system may avoid calling {@link #onSaveInstanceState} on activity A if it isn't
     * killed during the lifetime of B since the state of the user interface of
     * A will stay intact.
     *
     * <p>The default implementation takes care of most of the UI per-instance
     * state for you by calling {@link android.view.View#onSaveInstanceState()} on each
     * view in the hierarchy that has an id, and by saving the id of the currently
     * focused view (all of which is restored by the default implementation of
     * {@link #onRestoreInstanceState}).  If you override this method to save additional
     * information not captured by each individual view, you will likely want to
     * call through to the default implementation, otherwise be prepared to save
     * all of the state of each view yourself.
     *
     * <p>If called, this method will occur before {@link #onStop}.  There are
     * no guarantees about whether it will occur before or after {@link #onPause}.
     * 
     * @param outState Bundle in which to place your saved state.
     * 
     * @see #onCreate
     * @see #onRestoreInstanceState
     * @see #onPause
     */
    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);
    }

/**
     * This method is called after {@link #onStart} when the activity is
     * being re-initialized from a previously saved state, given here in
     * <var>savedInstanceState</var>.  Most implementations will simply use {@link #onCreate}
     * to restore their state, but it is sometimes convenient to do it here
     * after all of the initialization has been done or to allow subclasses to
     * decide whether to use your default implementation.  The default
     * implementation of this method performs a restore of any view state that
     * had previously been frozen by {@link #onSaveInstanceState}.
     * 
     * <p>This method is called between {@link #onStart} and
     * {@link #onPostCreate}.
     * 
     * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
     * 
     * @see #onCreate
     * @see #onPostCreate
     * @see #onResume
     * @see #onSaveInstanceState
     */
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mWindow != null) {
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
                mWindow.restoreHierarchyState(windowState);
            }
        }
    }

这些都和状态保存相关系的~值得深入理解一下

比如在HorizontalScrollView 中的最后一段代码,就用来保存View的状态:

static class SavedState extends BaseSavedState {
        public int scrollPosition;
        public boolean isLayoutRtl;

        SavedState(Parcelable superState) {
            super(superState);
        }

        public SavedState(Parcel source) {
            super(source);
            scrollPosition = source.readInt();
            isLayoutRtl = (source.readInt() == 0) ? true : false;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(scrollPosition);
            dest.writeInt(isLayoutRtl ? 1 : 0);
        }

        @Override
        public String toString() {
            return "HorizontalScrollView.SavedState{"
                    + Integer.toHexString(System.identityHashCode(this))
                    + " scrollPosition=" + scrollPosition
                    + " isLayoutRtl=" + isLayoutRtl + "}";
        }

        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

 

http://blog.csdn.net/murongshusheng/article/details/8199538

这里总结了很多细节,我之前就疏忽了为什么按back键就不保存状态呢?原来不是什么时候都保存状态的。

1.在一个activity被销毁前,不一定会调用onSaveInstanceState()这个方法,因为不是所有情况都需要去存储activity的状态(例如当用户按回退键退出你的activity的时候,因为用户指定关掉这个activity)。


2.如果这个方法被调用,它一定会在 onStop()方法之前,可能会在onPause()方法之前。


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


4.由于默认的onSaveInstanceState()方法的实现帮助UI存储它的状态,所以如果你需要覆盖这个方法去存储额外的状态信息时,你应该在执行任何代码之前都调用父类的onSaveInstanceState()方法(super.onSaveInstanceState())。


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


文章链接:http://blog.csdn.net/murongshusheng/article/details/8199538

实例,写的很棒:是一个自定义View SaveState的例子,非常好。

http://disanji.net/2011/04/28/android-view-onsaveinstancestate-onrestoreinstancestate/ 


后面主要写写Activity onSaveInstanceState 和 onRestoreInstanceState 方法使用注意事项,我觉得这个地方非常重要:


在Activity中,有两个方法用于临时保存、恢复状态信息,注意是临时信息,如果你关机重启肯定保存不了。这两个方法是:

  • public void onSaveInstanceState(Bundle savedInstanceState);
  • public void onRestoreInstanceState(Bundle savedInstanceState);  
     

在写Demo测试Activity生命周期的时候,发现onRestoreInstanceState方法并不会总是被调用,上网查了一下,这两个方法主要用于在切换屏幕布局时保存APP数据的,文章中提到“如果我们的Activity在后台没有因为运行内存吃紧被清理,则切换回时会触发onRestoreInstanceState方法”。因为内存回收不受我们控制,所以在除了在切换屏幕保存数据状态以外,最好使用onPause方法和onResume方法来保存和读取程序状态。

以下几种情况会调用onSaveInstanceState,分别是:

  • 用户按下HOME键;
  • 长按HOME键,选择运行其他的程序;
  • 按下电源按键;
  • 屏幕方向切换(可能);
  • 启动新的Activity等;

适合临时信息:当要保存持久信息时,不要使用这个保存方法!举个简单的例子,当我们点击Home后,onSaveInstanceState方法会被调用,此时,如果从Settings里面终止程序,那么,回来后发现保存的数据是不存在的。

至于这两个函数的使用,给出示范代码(留意自定义代码在调用super的前或后):

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putBoolean("MyBoolean", true);
        savedInstanceState.putDouble("myDouble", 1.9);
        savedInstanceState.putInt("MyInt", 1);
        savedInstanceState.putString("MyString", "Welcome back to Android");
        // etc.
        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");
}

参考:(下面的链接都非常有价值)

http://blog.csdn.net/ddna/article/details/5123482

http://blog.csdn.net/spare_h/article/details/6659010

http://android.blog.51cto.com/268543/634646/

http://www.th7.cn/Program/Android/201312/162981.shtml

http://www.charlesharley.com/2012/programming/views-saving-instance-state-in-android/

http://stackoverflow.com/questions/3542333/how-to-prevent-custom-views-from-losing-state-across-screen-orientation-changes

http://stackoverflow.com/questions/14891434/overriding-view-onsaveinstancestate-and-view-onrestoreinstancestate-using-vi

https://github.com/CharlesHarley/Example-Android-SavingInstanceState/blob/master/src/com/example/android/savinginstancestate/views/LockCombinationPicker.java

抱歉!评论已关闭.