还在用public static T 保存View状态?
Android官方早已想到了:
使用View.BaseSavedState
来保存状态。
在一个activity被销毁前,不一定会调用onSaveInstanceState()这个方法,因为不是所有情况都需要去存储activity的状态(例如当用户按回退键退出你的activity的时候,因为用户指定关掉这个activity)。
如果这个方法被调用,它一定会在 onStop()方法之前,可能会在onPause()方法之前。
布局中的每一个View默认实现了onSaveInstanceState()方法,这样的话,这个UI的任何改变都会自动的存储和在activity重新创建的时候自动的恢复。但是这种情况只有在你为这个UI提供了唯一的ID之后才起作用,如果没有提供ID,将不会存储它的状态。
由于默认的onSaveInstanceState()方法的实现帮助UI存储它的状态,所以如果你需要覆盖这个方法去存储额外的状态信息时,你应该在执行任何代码之前都调用父类的onSaveInstanceState()方法(super.onSaveInstanceState())。
由于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
读取保存状态
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 CREATOR = new Parcelable.Creator() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
我们看一下它的构造方法
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 CREATOR =
new Parcelable.Creator() {
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 CREATOR
= new Parcelable.Creator() {
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 CREATOR = new Parcelable.Creator() {
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 }