看项目代码时发现View和AbsListView中同样有onSaveInstanceState和onRestoreInstanceState方法
这两个类中的onSaveInstanceState()方法与Activity类的有些不同,当然原理和用途都是一致,都是为了保存控件当前的一些状态。
Activity中:
/** * 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); }view中:
/** * Hook allowing a view to generate a representation of its internal state * that can later be used to create a new instance with that same state. * This state should only contain information that is not persistent or can * not be reconstructed later. For example, you will never store your * current position on screen because that will be computed again when a * new instance of the view is placed in its view hierarchy. * <p> * Some examples of things you may store here: the current cursor position * in a text view (but usually not the text itself since that is stored in a * content provider or other persistent storage), the currently selected * item in a list view. * * @return Returns a Parcelable object containing the view's current dynamic * state, or null if there is nothing interesting to save. The * default implementation returns null. * @see #onRestoreInstanceState(android.os.Parcelable) * @see #saveHierarchyState(android.util.SparseArray) * @see #dispatchSaveInstanceState(android.util.SparseArray) * @see #setSaveEnabled(boolean) */ protected Parcelable onSaveInstanceState() { mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; return BaseSavedState.EMPTY_STATE; }
AbsListView中:
@Override public Parcelable onSaveInstanceState() { /* * This doesn't really make sense as the place to dismiss the * popups, but there don't seem to be any other useful hooks * that happen early enough to keep from getting complaints * about having leaked the window. */ dismissPopup(); Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); if (mPendingSync != null) { // Just keep what we last restored. ss.selectedId = mPendingSync.selectedId; ss.firstId = mPendingSync.firstId; ss.viewTop = mPendingSync.viewTop; ss.position = mPendingSync.position; ss.height = mPendingSync.height; ss.filter = mPendingSync.filter; ss.inActionMode = mPendingSync.inActionMode; ss.checkedItemCount = mPendingSync.checkedItemCount; ss.checkState = mPendingSync.checkState; ss.checkIdState = mPendingSync.checkIdState; return ss; } boolean haveChildren = getChildCount() > 0 && mItemCount > 0; long selectedId = getSelectedItemId(); ss.selectedId = selectedId; ss.height = getHeight(); if (selectedId >= 0) { // Remember the selection ss.viewTop = mSelectedTop; ss.position = getSelectedItemPosition(); ss.firstId = INVALID_POSITION; } else { if (haveChildren && mFirstPosition > 0) { // Remember the position of the first child. // We only do this if we are not currently at the top of // the list, for two reasons: // (1) The list may be in the process of becoming empty, in // which case mItemCount may not be 0, but if we try to // ask for any information about position 0 we will crash. // (2) Being "at the top" seems like a special case, anyway, // and the user wouldn't expect to end up somewhere else when // they revisit the list even if its content has changed. View v = getChildAt(0); ss.viewTop = v.getTop(); int firstPos = mFirstPosition; if (firstPos >= mItemCount) { firstPos = mItemCount - 1; } ss.position = firstPos; ss.firstId = mAdapter.getItemId(firstPos); } else { ss.viewTop = 0; ss.firstId = INVALID_POSITION; ss.position = 0; } } ss.filter = null; if (mFiltered) { final EditText textFilter = mTextFilter; if (textFilter != null) { Editable filterText = textFilter.getText(); if (filterText != null) { ss.filter = filterText.toString(); } } } ss.inActionMode = mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null; if (mCheckStates != null) { ss.checkState = mCheckStates.clone(); } if (mCheckedIdStates != null) { final LongSparseArray<Integer> idState = new LongSparseArray<Integer>(); final int count = mCheckedIdStates.size(); for (int i = 0; i < count; i++) { idState.put(mCheckedIdStates.keyAt(i), mCheckedIdStates.valueAt(i)); } ss.checkIdState = idState; } ss.checkedItemCount = mCheckedItemCount; if (mRemoteAdapter != null) { mRemoteAdapter.saveRemoteViewsCache(); } return ss; }从源码大致可以看出他们各自保存的数据并不同,这跟各个控件的用途特性有关。比如listview会对当前选中的item项位置进行保存,而View的其他一些子类比如Edittext由于存在光标,会对光标位置信息等进行保存。View和Abslistview的onsaveinstancestate方法返回的是Parcelable对象,Activity无返回。但不管返回的是什么,存储信息的都是Parcelable或其子类。
使用举例:
@Override protected void onPause() { super.onPause(); try { lv_friend_state = lv_friend.onSaveInstanceState(); } catch (RuntimeException e) { } }界面onpause时对listview状态进行保存
之后在onresume中恢复
@Override protected void onResume() { super.onResume(); lv_friend.onRestoreInstanceState(lv_friend_state); }以前开发遇到过类似要求页面跳转后回来重新请求网络数据后保持历史操作的一些界面不变,当时是通过记录listview等的item的position数据重新进行定位实现的。现在通过状态保存可以很方便的实现像Activity状态保存的类似需求,能够更方便的实现一些效果。
当然还有其他的一些类也有这些方法,没有仔细全找出来。相对应的onRestoreInstanceState里面的代码逻辑也相应各有不同,与onsaveinstancestate相呼应。