Android原理——SavedState

View.BaseSavedState


引言

还在用public static T 保存View状态?
Android官方早已想到了:
使用View的BaseSavedState来保存状态。

  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()方法中存储持久化数据(例如应该被存储到数据库中的数据)。


类概述

BaseSavedState
Base class for derived classes that want to save and restore their own state in onSaveInstanceState().

直接子类

TextView.SavedState
ViewPager.SavedState


How To Use

读取保存状态
onRestoreInstanceState(Parcelable state)
保存状态
Parcelable onSaveInstanceState()

举个ViewPager.SavedState的示例

    /**
     * 读取保存状态
     * */
    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState)state;
        super.onRestoreInstanceState(savedState.getSuperState());
        mCurrentPage = savedState.currentPage;
        mSnapPage = savedState.currentPage;
        requestLayout();
    }
    /**
     * 保存状态
     * */
    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.currentPage = mCurrentPage;
        return savedState;
    }

    /**
     * 保存界面状态
     * */
    static class SavedState extends BaseSavedState {
        //当前页
        int currentPage;

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

        private SavedState(Parcel in) {
            super(in);
            currentPage = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(currentPage);
        }

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

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


BaseSavedState源码

我们看一下它的构造方法

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];
            }
        };
    }

而其父类实现了Parcelable借口

/**
 * A {@link Parcelable} implementation that should be used by inheritance
 * hierarchies to ensure the state of all classes along the chain is saved.
 */
public abstract class AbsSavedState implements Parcelable {
    public static final AbsSavedState EMPTY_STATE = new AbsSavedState() {};

    private final Parcelable mSuperState;

    /**
     * Constructor used to make the EMPTY_STATE singleton
     */
    private AbsSavedState() {
        mSuperState = null;
    }

    /**
     * Constructor called by derived classes when creating their SavedState objects
     * 
     * @param superState The state of the superclass of this view
     */
    protected AbsSavedState(Parcelable superState) {
        if (superState == null) {
            throw new IllegalArgumentException("superState must not be null");
        }
        mSuperState = superState != EMPTY_STATE ? superState : null;
    }

    /**
     * Constructor used when reading from a parcel. Reads the state of the superclass.
     * 
     * @param source
     */
    protected AbsSavedState(Parcel source) {
        // FIXME need class loader
        Parcelable superState = source.readParcelable(null);

        mSuperState = superState != null ? superState : EMPTY_STATE;
    }

    final public Parcelable getSuperState() {
        return mSuperState;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(mSuperState, flags);
    }

    public static final Parcelable.Creator<AbsSavedState> CREATOR 
        = new Parcelable.Creator<AbsSavedState>() {

        public AbsSavedState createFromParcel(Parcel in) {
            Parcelable superState = in.readParcelable(null);
            if (superState != null) {
                throw new IllegalStateException("superState must be null");
            }
            return EMPTY_STATE;
        }

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

补充

最后再举一个定义SeekBar的

3   import android.content.Context;
4   import android.content.res.TypedArray;
5   import android.os.Parcel;
6   import android.os.Parcelable;
7   import android.util.AttributeSet;
8   import android.view.View;
9   import android.view.ViewGroup;
10  import android.view.ViewParent;
11  
12  import com.WazaBe.HoloEverywhere.LayoutInflater;
13  import com.WazaBe.HoloEverywhere.R;
14  import com.WazaBe.HoloEverywhere.widget.SeekBar;
15  
16  public class SeekBarDialogPreference extends DialogPreference {
17      private static class SavedState extends BaseSavedState {
18          @SuppressWarnings("unused")
19          public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
20              @Override
21              public SavedState createFromParcel(Parcel in) {
22                  return new SavedState(in);
23              }
24  
25              @Override
26              public SavedState[] newArray(int size) {
27                  return new SavedState[size];
28              }
29          };
30  
31          protected int mValue, mMaxValue;
32  
33          public SavedState(Parcel source) {
34              super(source);
35              mValue = source.readInt();
36              mMaxValue = source.readInt();
37          }
38  
39          public SavedState(Parcelable superState) {
40              super(superState);
41          }
42  
43          @Override
44          public void writeToParcel(Parcel dest, int flags) {
45              super.writeToParcel(dest, flags);
46              dest.writeInt(mValue);
47              dest.writeInt(mMaxValue);
48          }
49      }
50  
51      private final SeekBar mSeekBar;
52      private int mValue = Integer.MIN_VALUE, mMaxValue = Integer.MIN_VALUE;
53  
54      public SeekBarDialogPreference(Context context) {
55          this(context, null);
56      }
57  
58      public SeekBarDialogPreference(Context context, AttributeSet attrs) {
59          this(context, attrs, R.attr.seekBarDialogPreferenceStyle);
60      }
61  
62      public SeekBarDialogPreference(Context context, AttributeSet attrs,
63              int defStyle) {
64          super(context, attrs, defStyle);
65          TypedArray a = context.obtainStyledAttributes(attrs,
66                  R.styleable.SeekBarDialogPreference, defStyle,
67                  R.style.Holo_PreferenceDialog_SeekBarDialogPreference);
68          int maxValue = a.getInt(R.styleable.SeekBarDialogPreference_max, 100);
69          a.recycle();
70          mSeekBar = onCreateSeekBar();
71          setMaxValue(maxValue);
72      }
73  
74      public int getMaxValue() {
75          return mMaxValue;
76      }
77  
78      public SeekBar getSeekBar() {
79          return mSeekBar;
80      }
81  
82      public int getValue() {
83          return mValue;
84      }
85  
86      @Override
87      protected void onBindDialogView(View view) {
88          super.onBindDialogView(view);
89          synchronized (mSeekBar) {
90              ViewParent oldParent = mSeekBar.getParent();
91              if (oldParent != view) {
92                  if (oldParent != null) {
93                      ((ViewGroup) oldParent).removeView(mSeekBar);
94                  }
95                  ((ViewGroup) view).addView(mSeekBar);
96              }
97          }
98      }
99  
100     protected SeekBar onCreateSeekBar() {
101         return (SeekBar) LayoutInflater.inflate(getContext(),
102                 R.layout.preference_dialog_seekbar_widget);
103     }
104 
105     @Override
106     protected void onDialogClosed(boolean positiveResult) {
107         super.onDialogClosed(positiveResult);
108         final int value;
109         synchronized (mSeekBar) {
110             value = mSeekBar.getProgress();
111         }
112         if (positiveResult && callChangeListener(value)) {
113             setValue(value);
114         }
115     }
116 
117     @Override
118     protected Integer onGetDefaultValue(TypedArray a, int index) {
119         return a.getInt(index, 0);
120     }
121 
122     @Override
123     protected void onRestoreInstanceState(Parcelable state) {
124         if (state == null || !(state instanceof SavedState)) {
125             super.onRestoreInstanceState(state);
126             return;
127         }
128         SavedState ss = (SavedState) state;
129         super.onRestoreInstanceState(ss.getSuperState());
130         setValue(ss.mValue);
131         setMaxValue(ss.mMaxValue);
132     }
133 
134     @Override
135     protected Parcelable onSaveInstanceState() {
136         final Parcelable superState = super.onSaveInstanceState();
137         if (isPersistent()) {
138             return superState;
139         }
140         final SavedState myState = new SavedState(superState);
141         myState.mValue = mValue;
142         myState.mMaxValue = mMaxValue;
143         return myState;
144     }
145 
146     @Override
147     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
148         int def = defaultValue instanceof Integer ? (Integer) defaultValue
149                 : defaultValue == null ? 0 : Integer.parseInt(defaultValue
150                         .toString());
151         mSeekBar.setProgress(restoreValue ? getPersistedInt(def) : def);
152     }
153 
154     public void setMaxValue(int maxValue) {
155         if (mMaxValue == maxValue) {
156             return;
157         }
158         final boolean wasBlocking = shouldDisableDependents();
159         mMaxValue = maxValue;
160         mSeekBar.setMax(maxValue);
161         if (shouldDisableDependents() != wasBlocking) {
162             notifyDependencyChange(!wasBlocking);
163         }
164     }
165 
166     public void setValue(int value) {
167         if (mValue == value) {
168             return;
169         }
170         final boolean wasBlocking = shouldDisableDependents();
171         mValue = value;
172         mSeekBar.setProgress(value);
173         persistInt(value);
174         if (shouldDisableDependents() != wasBlocking) {
175             notifyDependencyChange(!wasBlocking);
176         }
177     }
178 }

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。