Solved...
I have a composite view that contains some other controls. I am trying to override save onSaveInstanceState
and onRestoreInstanceState
, but am getting a strange result.
The Parcelable state
argument to onRestoreInstanceState
is not of my custom sub-class of BaseSavedState
, SavedState
and always seem to be BaseSavedState.EMPTY_STATE
. (Look for the "always fails" code comment below...
It seems that the problem is likely with the save portion, as the SavedState.writeToParcel
is not being called after onSaveInstanceState enters.
Almost as if whoever is calling onSaveInstanceState
is throwing the result away before persisting it to the Parcel
.
If it makes a difference, this view is hosted inside a fragment.
Any ideas?
Here is my class definition:
public class AddressInput extends FrameLayout
Here is my onSaveInstanceState
and onRestoreInstanceState
pair:
@Override
protected Parcelable onSaveInstanceState()
{
// Return saved state
Parcelable superState = super.onSaveInstanceState();
return new AddressInput.SavedState( superState, mCurrentLookUp );
}
@Override
protected void onRestoreInstanceState( Parcelable state )
{
// **** (state == BaseSavedState.EMPTY_STATE) is also always true
// Cast state to saved state
if ( state instance of AddressInput.SavedState ) // **** <--- always fails
{
AddressInput.SavedState restoreState = (AddressInput.SavedState)state;
// Call super with its portion
super.onRestoreInstanceState( restoreState.getSuperState() );
// Get current lookup
mCurrentLookUp = restoreState.getCurrentLookup();
}
else
// Just send to super
super.onRestoreInstanceState( state );
}
Here's my custom BaseSavedState
sub-class (inner class of AddressInput
) :
public static class SavedState extends BaseSavedState
{
private String mCurrentLookup;
public SavedState(Parcelable superState, String currentLookup)
{
super(superState);
mCurrentLookup = currentLookup;
}
private SavedState(Parcel in)
{
super(in);
this.mCurrentLookup = in.readString();
}
public String getCurrentLookup()
{
return mCurrentLookup;
}
@Override
public void writeToParcel(Parcel out, int flags)
{
super.writeToParcel(out, flags);
out.writeString( this.mCurrentLookup );
}
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>()
{
public AddressInput.SavedState createFromParcel(Parcel in)
{
return new AddressInput.SavedState(in);
}
public AddressInput.SavedState[] newArray(int size) {
return new AddressInput.SavedState[size];
}
};
}
Figured it out... My custom view had the same ID for its
FrameLayout
as was being used for the specific instance of the custom view. The state was being properly saved by the instance and then overwritten (cleared) by theFrameLayout
which had no state to persist.I also changed its base-class to a
RelativeView
which made more sense.In custom view's XML:
And the instance usage:
Changed to: (@+id/addressInput -> @+id/shippingAddress)
Makes you wish there was some scoping for IDs to prevent this kind of thing. Why should you have to know about a custom view's internals to make sure you avoid ID conflict?