保存状态在屏幕上旋转时,化合物成分多次使用化合物、成分、状态、屏幕上

2023-09-05 10:14:14 作者:晴栀°

我现在面临一个问题,我知道的根本原因,但没有看到一个方法来解决它。如果自定义复合组件在一个活动中多次使用,免于意见的值会相互覆盖。为了解释更方便我做了下面的例子。

I'm facing a problem where I know the root cause but don't see a way to fix it. If a custom compound component is used multiple times in an activity, the values saved from views will overwrite each other. To explain it easier I made the following example.

在XML的新组件,只有一个EditText把它缩短。

The xml for the new component, only an EditText to make it shorter.

<?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>

本类实现新的行为,只有膨胀的布局。

The class implementing the new behavior, only inflating the layout.

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>

当屏幕旋转时,从第二视图中的值也恢复中的第一个。

When the screen is rotated, the value from second View is also restored in the first one.

挖掘到框架中的code我发现Parcelable物体的onSaveInstanceState返回的视图类中定义被放在一个SparseArray与主要对象的ID。因为我包括CustomView多次ID为custom_text的EditText上也越来越多次添加。具有相同的ID,值保存会相互覆盖。

Digging into the framework's code I found out that Parcelable objects returned from onSaveInstanceState defined in View class are put in a SparseArray with the key object's id. Because I'm including CustomView multiple times the EditText with id "custom_text" is also getting added multiple times. Having the same id, values saved will overwrite each other.

我正在寻找任何建议如何这应该是实际执行。现在,我看不出有什么办法来改变这些标识符。

I'm looking for any suggestion on how this should be actually implemented. Right now, I don't see any way to change those identifiers.

推荐答案

好像我有这个问题的一些解决方案。我试图寻找了一段时间。 1.首先,你必须创建一个扩展BaseSavedState内部类,你CustomView里面。

Seems like i have some solution with this problem. I try to find it for some time. 1.First you must create inner class which extends BaseSavedState, inside your CustomView.

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.then覆盖CustomView这两种方法

2.then override this two methods in 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.override onAttachedToWindow(),并设置为EDITTEXT价值。

3.override onAttachedToWindow() and set to edittext "value".

CustomView{
     String value;  //some text value from edittext 

     EditText edittext;

     ...
     @Override
     protected void onAttachedToWindow() {
           edittext.setText(value);
           super.onAttachedToWindow();
     }
     ...
}

,现在你可以有你的自定义视图的能够抵抗改变方向的多个实例 - 他们将有正确的values​​.I没有测试该解决方案在100%,但它似乎是不错的。 ...索里对我的索里,我的英语。)

and now you can have multiple instances of your Custom View 's that are resistant to change orientation - they will have the correct values.I have not tested this solution in 100% but it seems to be good. ... sory for my sory for my english;).