我遇到一个问题,我知道根本原因,但没有办法解决它。如果在活动中多次使用自定义复合组件,则从视图中保存的值将相互覆盖。为了便于解释,我做了以下示例。
新组件的xml,只有一个EditText可以缩短它。
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<EditText
android:id="@+id/custom_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" >
</EditText>
</merge>
实现新行为的类,只是给布局充气。
public class CustomView extends LinearLayout {
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_view, this, true);
}
}
使用其中2个布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<test.customview.CustomView
android:id="@+id/customView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</test.customview.CustomView>
<test.customview.CustomView
android:id="@+id/customView2"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</test.customview.CustomView>
</LinearLayout>
旋转屏幕时,第二个视图中的值也会在第一个视图中恢复。
深入研究框架的代码,我发现从View类中定义的onSaveInstanceState返回的Parcelable对象被放入一个带有密钥对象id的SparseArray中。因为我多次包含CustomView,ID为“custom_text”的EditText也会多次添加。拥有相同的ID,保存的值将相互覆盖。
我正在寻找关于如何实际实施的任何建议。现在,我认为没有办法改变这些标识符。
答案 0 :(得分:2)
好像我有一些解决这个问题的方法。我试着找一段时间。
1.首先,您必须在CustomView中创建扩展BaseSavedState的内部类。
CustomView{
String value; //some text value from edittext
EditText edittext;
...
private static class Save extends BaseSavedState{
String savedValue;
public Save(Parcel incoming) {
super(incoming);
savedValue = incoming.readString();
Log.i("Save", "Parcel");
}
public Save(Parcelable parcelable) {
super(parcelable);
Log.i("Save", "Parcelable");
}
@Override
public void writeToParcel(Parcel outcoming, int flags) {
super.writeToParcel(outcoming, flags);
outcoming.writeString(savedValue );
Log.i("Save", "writeToParcel");
}
public static final Parcelable.Creator<Save> CREATOR =
new Creator<CustomView.Save>() {
@Override
public Save[] newArray(int size) {
Log.i("Parcelable.Creator<Save>", "newArray");
return new Save[size];
}
@Override
public Save createFromParcel(Parcel incoming) {
Log.i("Parcelable.Creator<Save>", "createFromParcel");
return new Save(incoming);
}
};
}
}
2.然后在CustomView
中覆盖这两个方法CustomView{
String value; //some text value from edittext
EditText edittext;
...
@Override
protected Parcelable onSaveInstanceState() {
Log.i("CustomView", "onSaveInstanceState");
Parcelable p = super.onSaveInstanceState();
Save save = new Save(p);
save.savedValue = value; // value is from CustomView class
return save;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Log.i("CustomView", "onRestoreInstanceState");
if(!(state instanceof Save)){
super.onRestoreInstanceState(state);
return;
}
Save save = (Save) state;
value = save.savedValue;
//setting in this place value to edittext will not do anything.
//instead, you have to do this in step 3
super.onRestoreInstanceState(save.getSuperState());
}
...
}
3.覆盖onAttachedToWindow()并设置为edittext“value”。
CustomView{
String value; //some text value from edittext
EditText edittext;
...
@Override
protected void onAttachedToWindow() {
edittext.setText(value);
super.onAttachedToWindow();
}
...
}
现在您可以拥有多个自定义视图实例,这些实例可以抵抗更改方向 - 它们将具有正确的值。我没有100%测试此解决方案,但似乎很好。