How to Prevent Custom Views from Losing State Across Screen Orientation Changes

How to prevent custom views from losing state across screen orientation changes

You do this by implementing View#onSaveInstanceState and View#onRestoreInstanceState and extending the View.BaseSavedState class.

public class CustomView extends View {

private int stateToSave;

...

@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.stateToSave = this.stateToSave;

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.stateToSave = ss.stateToSave;
}

static class SavedState extends BaseSavedState {
int stateToSave;

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

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

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

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

The work is split between the View and the View's SavedState class. You should do all the work of reading and writing to and from the Parcel in the SavedState class. Then your View class can do the work of extracting the state members and doing the work necessary to get the class back to a valid state.

Notes: View#onSavedInstanceState and View#onRestoreInstanceState are called automatically for you if View#getId returns a value >= 0. This happens when you give it an id in xml or call setId manually. Otherwise you have to call View#onSaveInstanceState and write the Parcelable returned to the parcel you get in Activity#onSaveInstanceState to save the state and subsequently read it and pass it to View#onRestoreInstanceState from Activity#onRestoreInstanceState.

Another simple example of this is the CompoundButton

How to prevent Custom Views from losing state across screen orientation changes for Mono for Android

I don't know if you want to do is possible or not but I do know that at this time a translation of the example java code is not possible because it is using Parcelable.

Below is an excerpt from the mono for android limitations page which can be viewed here

Android.OS.IParcelable cannot be implemented.

The IParcelable interface cannot be implemented at this time because the android.os.Parcelable interface requires:

Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator interface.

Since mandroid.exe currently cannot generate fields, this interface cannot be implemented. Support will be added in a future release.

Android compound views render incorrectly when screen orientation changes

What you need it save your CustomViews State , when you Change the orientation of the device the android OS initialize your view from the beginning so try to implements in your view methods

onSaveInstanceState 

which will called by onpause method before the orientation changed and here you will save your data from edittext

and

onRestoreInstanceState

which will called after the orientation done and add the correct data to your views

and here full code :

How to prevent custom views from losing state across screen orientation changes

Android Custom View (Bitmap) losing data when screen is rotated

You will need to implement your own version of SavedState as an inner class of your custom view. It's a bit verbose as it has to implement Parcelable. It would be something like:

@Override
protected Parcelable onSaveInstanceState() {

return new SavedState(
super.onSaveInstanceState(),
customBitmap,
stuff
);
}

@Override
protected void onRestoreInstanceState(Parcelable state) {

SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());

stuff = savedState.getStuff();
customBitmap = savedState.getBitmap();
}

protected static class SavedState extends BaseSavedState {

private final Bitmap bitmap;
private final int stuff;

public SavedState(Parcelable superState, Bitmap bitmap, int stuff) {
super(superState);
this.bitmap = bitmap;
this.stuff = stuff;
}

public SavedState(Parcel source) {
super(source);
this.bitmap = Bitmap.CREATOR.createFromParcel(source);
this.stuff = source.readInt();
}

public Bitmap getBitmap() {return bitmap;}
public int getStuff() {return stuff;}

@Override
public void writeToParcel(Parcel destination, int flags) {

super.writeToParcel(destination, flags);
bitmap.writeToParcel(destination, 0);
destination.writeInt(stuff);
}

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

public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}

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

};
}

How to handle Spinners when screen orientation changes?

Add android:configChanges="orientation|screenSize" in your AndroidManifest file, it will keep spinner value selected on orientation change.

User Spinner Like this:

mSpinner = findViewById(R.id.spinner);

ArrayList<String> stringArrayList = new ArrayList<>();

for (int i = 0; i < 6; i++) {

stringArrayList.add("List Item " + i);

}

ArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, stringArrayList);
spinner.setAdapter(arrayAdapter);


Related Topics



Leave a reply



Submit