Managing View State in Android: Techniques and Approaches
satya - Wed Oct 24 2012 08:51:04 GMT-0400 (Eastern Daylight Time)
Managing View State in Android: Techniques and Approaches
Managing View State in Android: Techniques and Approaches
Search for: Managing View State in Android: Techniques and Approaches
satya - Wed Oct 24 2012 08:52:34 GMT-0400 (Eastern Daylight Time)
Here is a discussion on sof
satya - Wed Oct 24 2012 08:54:37 GMT-0400 (Eastern Daylight Time)
What is Android BaseSavedState
What is Android BaseSavedState
satya - Wed Oct 24 2012 08:58:22 GMT-0400 (Eastern Daylight Time)
Here are a couple of examples using onSaveInstanceState
satya - Wed Oct 24 2012 08:59:07 GMT-0400 (Eastern Daylight Time)
The nagging issue is the view has to have an ID
And if the view is reused or forget to put the ID then state is not saved...
satya - Wed Oct 24 2012 09:00:32 GMT-0400 (Eastern Daylight Time)
Key APIs seem to be
onSaveInstanceState
saveHierarchyState
dispatchSaveInstanceState
setSaveEnabled
BaseSavedState
satya - Wed Oct 24 2012 09:00:50 GMT-0400 (Eastern Daylight Time)
Another approach is to have the activity or fragment explicitly invoke a save and restore
Another approach is to have the activity or fragment explicitly invoke a save and restore
satya - Wed Oct 24 2012 09:01:52 GMT-0400 (Eastern Daylight Time)
onSaveInstanceState Romain
onSaveInstanceState Romain
satya - Wed Oct 24 2012 09:08:53 GMT-0400 (Eastern Daylight Time)
Here is another worthy thread from developers group
satya - Wed Oct 24 2012 09:10:22 GMT-0400 (Eastern Daylight Time)
A quick approach if you are using the native view's state capabilities
override the onsaveinstancestate
Create your own bundle
use the return from the super and place it in your bundle
Do the reverse in onrestore...
Make sure to take into account null from the super class
satya - Wed Oct 24 2012 09:11:34 GMT-0400 (Eastern Daylight Time)
Here are some notes from Dianne on subclassing textview in 2008
A static variable is almost certainly not going to do what you want -- one of the big reasons for all of this is to be able to restore state if the process is killed, and if you are putting stuff in a static variable then that will all go away with the process when it is killed.
Unfortunately it does look like there is an issue in TextView with this, which I will need to think about how to fix. There are a lot of optimizations going on to avoid creating, saving, and restoring state objects unless they are needed... unfortunately this causes trouble for people deriving from TextView. Technically what you are supposed to do is take the state object returned by the super class, write it in your own state object, and hand it back to the super class when restoring state. The optimization to return null when there is no state to save is breaking that.
One simple thing you could do is call TextView.setFreezesText() when you are initializing your subclass. This tells the text view it should store its entire text in the state, which will force it to always save its state.
satya - Wed Oct 24 2012 09:14:45 GMT-0400 (Eastern Daylight Time)
Android pattern for using BaseSavedState
Android pattern for using BaseSavedState
satya - Wed Oct 24 2012 09:18:02 GMT-0400 (Eastern Daylight Time)
This example uses that pattern
satya - Wed Oct 24 2012 09:20:31 GMT-0400 (Eastern Daylight Time)
Here is the View's inner class BaseSavedState
public static class BaseSavedState extends AbsSavedState {
/**
* Constructor used when reading from a parcel. Reads the state of the superclass.
*
* @param source
*/
public BaseSavedState(Parcel source) {
super(source);
}
/**
* Constructor called by derived classes when creating their SavedState objects
*
* @param superState The state of the superclass of this view
*/
public BaseSavedState(Parcelable superState) {
super(superState);
}
public static final Parcelable.Creator<BaseSavedState> CREATOR =
new Parcelable.Creator<BaseSavedState>() {
public BaseSavedState createFromParcel(Parcel in) {
return new BaseSavedState(in);
}
public BaseSavedState[] newArray(int size) {
return new BaseSavedState[size];
}
};
}
satya - Wed Oct 24 2012 09:29:25 GMT-0400 (Eastern Daylight Time)
android Parcelable CREATOR pattern
android Parcelable CREATOR pattern
satya - Wed Oct 24 2012 09:29:37 GMT-0400 (Eastern Daylight Time)
Bam! here is the link
satya - Wed Oct 24 2012 09:33:28 GMT-0400 (Eastern Daylight Time)
managing view state
managing view state
Search Google for: managing view state
Search Android Developers Group for: managing view state
Search Android Beginers Group for: managing view state
satya - Wed Oct 24 2012 09:46:33 GMT-0400 (Eastern Daylight Time)
dispatchSaveInstanceState
dispatchSaveInstanceState
satya - Wed Oct 24 2012 09:48:18 GMT-0400 (Eastern Daylight Time)
Here is a formal document from Charles Harley
satya - Wed Oct 24 2012 09:54:42 GMT-0400 (Eastern Daylight Time)
dispatchFreezeSelfOnly
dispatchFreezeSelfOnly
satya - Wed Oct 24 2012 10:07:18 GMT-0400 (Eastern Daylight Time)
Here is one of the methods of ViewGrouop
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
View c = children[i];
if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
c.dispatchSaveInstanceState(container);
}
}
}
satya - Wed Oct 24 2012 10:08:14 GMT-0400 (Eastern Daylight Time)
The knarly part is this
protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
}
satya - Wed Oct 24 2012 10:09:16 GMT-0400 (Eastern Daylight Time)
Here is the super class method
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();
if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
// Log.i("View", "Freezing #" + Integer.toHexString(mID)
// + ": " + state);
container.put(mID, state);
}
}
}
satya - Wed Oct 24 2012 10:09:49 GMT-0400 (Eastern Daylight Time)
I finally get this knarly string!!!
I finally get this knarly string!!!
satya - Wed Oct 24 2012 13:14:50 GMT-0400 (Eastern Daylight Time)
Here is how textview implements the SavedState
public static class SavedState extends BaseSavedState {
int selStart;
int selEnd;
CharSequence text;
boolean frozenWithFocus;
CharSequence error;
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(selStart);
out.writeInt(selEnd);
out.writeInt(frozenWithFocus ? 1 : 0);
TextUtils.writeToParcel(text, out, flags);
if (error == null) {
out.writeInt(0);
} else {
out.writeInt(1);
TextUtils.writeToParcel(error, out, flags);
}
}
@Override
public String toString() {
String str = "TextView.SavedState{"
+ Integer.toHexString(System.identityHashCode(this))
+ " start=" + selStart + " end=" + selEnd;
if (text != null) {
str += " text=" + text;
}
return str + "}";
}
@SuppressWarnings("hiding")
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];
}
};
private SavedState(Parcel in) {
super(in);
selStart = in.readInt();
selEnd = in.readInt();
frozenWithFocus = (in.readInt() != 0);
text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
if (in.readInt() != 0) {
error = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
}
}
}
satya - Wed Oct 24 2012 13:17:50 GMT-0400 (Eastern Daylight Time)
Here is how it is used in the onSavedInstance
Parcelable superStae = super.onS...();
ss = new SavedState(superState);
ss.set..();
ss.set..();
return ss;
simple enough
satya - Wed Oct 24 2012 13:19:59 GMT-0400 (Eastern Daylight Time)
What happens first in restore
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
if you are not what I sent you let my super deal with it and return. Only recognize if it is me
satya - Wed Oct 24 2012 13:22:09 GMT-0400 (Eastern Daylight Time)
Then do this...
//cast it
SavedState ss = (SavedState)state;
//Call the super first
super.onRestoreInstanceState(ss.getSuperState());
ss.get..();
ss.get..();
//reinitialize your controls as if the view has just been
//created, if needed. Probably you do need.
- Wed Oct 24 2012 13:38:04 GMT-0400 (Eastern Daylight Time)
Here is my specific implementation
public class CircleView extends View
{
//state
//Remember this as device flipts
int defRadius;
.....
/*
* ***************************************************************
* Save and restore work
* ***************************************************************
*/
@Override
protected void onRestoreInstanceState(Parcelable p)
{
this.onRestoreInstanceStateStandard(p);
this.initCircleView();
}
@Override
protected Parcelable onSaveInstanceState()
{
return this.onSaveInstanceStateStandard();
}
/*
* ***************************************************************
* Use a simpler approach
* ***************************************************************
*/
private void onRestoreInstanceStateSimple(Parcelable p)
{
if (!(p instanceof Bundle))
{
throw new RuntimeException("unexpected bundle");
}
Bundle b = (Bundle)p;
defRadius = b.getInt("defRadius");
Parcelable sp = b.getParcelable("super");
//No need to call parent. It is just a base view
super.onRestoreInstanceState(sp);
}
private Parcelable onSaveInstanceStateSimple()
{
//Don't call the base class as it will return a null
Parcelable p = super.onSaveInstanceState();
Bundle b = new Bundle();
b.putInt("defRadius",defRadius);
b.putParcelable("super",p);
return b;
}
/*
* ***************************************************************
* Use a standard approach
* ***************************************************************
*/
private void onRestoreInstanceStateStandard(Parcelable state)
{
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
//it is our state
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
defRadius = ss.defRadius;
}
private Parcelable onSaveInstanceStateStandard()
{
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.defRadius = this.defRadius;
return ss;
}
/*
* ***************************************************************
* Saved State inner static class
* ***************************************************************
*/
public static class SavedState extends BaseSavedState {
int defRadius;
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(defRadius);
}
@Override
public String toString() {
return "CircleView defRadius:" + defRadius;
}
@SuppressWarnings("hiding")
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];
}
};
//Read back the values
private SavedState(Parcel in) {
super(in);
defRadius = in.readInt();
}
}//eof-state-class
}//eof-main-view class
satya - Wed Oct 31 2012 13:26:49 GMT-0400 (Eastern Daylight Time)
Counterpart of dispatchFreezeSelfOnly is dispatchThawSelfOnly
Counterpart of dispatchFreezeSelfOnly is dispatchThawSelfOnly