开发者

Android manage configuration changes(state) in custom view

This is follow up to: Android local variable get's lost when using camera intent

Proper way to do it is to handle onSaveInstanceState and onRestoreInstanceState like shown here:

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/CompoundButton.java

Here is my code:

static class SavedState extends BaseSavedState
    {
        private String requestedFileName;
        private UUID[] mImages = new UUID[4];

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

        private SavedState(Parcel in)
        {
      开发者_如何学Go    super(in);
        }

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

        //required field that makes Parcelables from a Parcel
        public static final Parcelable.Creator<SavedState> CREATOR =
            new Parcelable.Creator<SavedState>()
            {
              public SavedState createFromParcel(Parcel in)
              {
                return new SavedState(in);
              }
              public SavedState[] newArray(int size)
              {
                return new SavedState[size];
              }
        };

    }

    @Override
    public Parcelable onSaveInstanceState()
    {
        //begin boilerplate code that allows parent classes to save state
        Parcelable superState = super.onSaveInstanceState();

        SavedState ss = new SavedState(superState);
        //end

        ss.requestedFileName = this.requestedFileName;
        ss.mImages = this.mImages;

        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state)
    {
        //begin boilerplate code so parent classes can restore state
        if(!(state instanceof SavedState))
        {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState)state;
        super.onRestoreInstanceState(ss.getSuperState());
        //end

        this.requestedFileName = ss.requestedFileName;
        this.mImages = ss.mImages;

        RestoreImageState();
    }

Now to my question. This code seems to work properly and it handles all state changes without a problem. HOWEVER, if you look at SavedState.writeToParcel and SavedState.SavedState you will notice that I do not store my variables there. Do I have to? Why? Problem is that I understand how to wrteToParcel and my data types match. But reading out of parcel not so clear with complex types. And in my tests it wasn't called.

EDIT:

Does this look correct for save/retreive order?

private SavedState(Parcel in)
        {
          super(in);
          this.mName = in.readString();
          this.mIndex = in.readInt();
          this.mApplicableDamages = (String[])in.readValue(null);
          this.mSelectedDamages = (boolean[])in.readValue(null);                            
        }

        @Override
        public void writeToParcel(Parcel out, int flags)
        {
          super.writeToParcel(out, flags);
          out.writeString(this.mName);
          out.writeInt(this.mIndex);
          out.writeArray(this.mApplicableDamages);
          out.writeBooleanArray(this.mSelectedDamages);
        }


You have to save these variables in onSaveInstanceState() and restore them in onRestoreInstanceState() later if they're part of your view's state and you don't want to lose them when a parent activity is recreated.

The variables may be lost because when the configuration change happens the parent activity is destroyed and a new activity object is recreated. This new object is receive the previously saved state. And if you don't add some variables to the state the won't be restored.

As to the writing complex types to and reading the from Parcel you can implement Parcelable for some parts of the complex type. Or you can just decompose the complex type to the primitive (parcelable) fields and store this fields one by one. In your case UUID[] can be stored in Parcel as Serializable or you can convert UUID[] to ParcelUuid[] and store this array as parcelable array.

And a few words about SavedState implementation. The fields in SavedState will not be saved if you don't add them to Parcel. So you have to write the to Parcel in SavedState.writeToParcel() method. And also you need to read them back in SavedState(Parcel) constructor.

static class SavedState extends BaseSavedState
{
    private String requestedFileName;
    private UUID[] mImages = new UUID[4];

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

    private SavedState(Parcel in)
    {
        super(in);
        requestedFileName = in.readString();
        mImages = (UUID[])in.readSerializable();
    }

    @Override
    public void writeToParcel(Parcel out, int flags)
    {
        super.writeToParcel(out, flags);
        out.writeString(requestedFileName);
        out.writeSerializable(mImages);
    }

    //required field that makes Parcelables from a Parcel
    public static final Parcelable.Creator<SavedState> CREATOR =
        new Parcelable.Creator<SavedState>()
        {
            public SavedState createFromParcel(Parcel in)
            {
                return new SavedState(in);
            }

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜