view的onSaveInstanceState和onRestoreInstanceState
在View文档中对其的说明如下:
protected void onRestoreInstanceState (Parcelable state)
Since: API Level 1
Hook allowing a view to re-apply a representation of its internal state that had previously
been generated by onSaveInstanceState(). This function will never be called with a null state.
Parameters
state The frozen state that had previously been returned by onSaveInstanceState().
See Also
* onSaveInstanceState()
* restoreHierarchyState(SparseArray)
* dispatchRestoreInstanceState(SparseArray)
protected Parcelable onSaveInstanceState ()
Since: API Level 1
Hook allowing a view to generate a representation of its internal state
that can later be used to create a new instance with that same state.
This state should only contain information that is not persistent or can not be reconstructed later.
For example, you will never store your current position on screen because that will be computed again
when a new instance of the view is placed in its view hierarchy.
Some examples of things you may store here: the current cursor position in a text view
(but usually not the text itself since that is stored in a content provider or other persistent storage),
the currently selected item in a list view.
Returns
* Returns a Parcelable object containing the view's current dynamic state,
or null if there is nothing interesting to save. The default implementation returns null.
在TextView文档中对其的说明如下:
public void onRestoreInstanceState (Parcelable state)
Since: API Level 1
Hook allowing a view to re-apply a representation of its internal state
that had previously been generated by onSaveInstanceState().
This function will never be called with a null state.
Parameters
state The frozen state that had previously been returned by onSaveInstanceState().
public Parcelable onSaveInstanceState ()
Since: API Level 1
Hook allowing a view to generate a representation of its internal state
that can later be used to create a new instance with that same state.
This state should only contain information that is not persistent or can not be reconstructed later.
For example, you will never store your current position on screen
because that will be computed again when a new instance of the view is placed in its view hierarchy.
Some examples of things you may store here: the current cursor position
in a text view (but usually not the text itself since that is stored in a content provider
or other persistent storage), the currently selected item in a list view.
Returns
* Returns a Parcelable object containing the view's current dynamic state,
or null if there is nothing interesting to save. The default implementation returns null
在View和TextView中对onSaveInstanceState和onRestoreInstanceState的描述都差不多。
但是在View中,这两个函数是protected的,而在TextView中这两个函数是public的。在ListView中他们也是public的。
但在他们的文档比没说系统何时回调用这两个函数。从在View的子类TextView和ListView中,都把他们声明为public的来看,
该两个函数应该不是由系统来调用的。从实例1的运行来看,也没发现系统调用它们。
因此它们应该只是设计作为一个接口,
以便在Activity的onSaveInstanceState(Bundle outState)和onRestoreInstanceState(Bundle savedInstanceState)中
调用来保存View的数据。
如何使用
对onSaveInstanceState (),是在函数里面保存一些View有用的数据到一个Parcelable对象,并返回。
在Activity的onSaveInstanceState(Bundle outState)中调用View的onSaveInstanceState (),返回Parcelable对象,
接着用Bundle的putParcelable方法保存在Bundle savedInstanceState中。
当系统调用Activity的的onRestoreInstanceState(Bundle savedInstanceState)时,
同过Bundle的getParcelable方法得到Parcelable对象,然后把该Parcelable对象传给View的onRestoreInstanceState (Parcelable state).
在的View的onRestoreInstanceState中从Parcelable读取保存的数据以便View使用
实例1
文件1:
Hello.java
package com.teleca;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class Hello extends Activity {
String tag="hubin";
MyTextView textView1;
MyTextView tv2;
final String kTextView1Name="tv1";
LinearLayout layoutRoot=null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.Button01);
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
Intent intent =new Intent(Hello.this,Hello2.class);
startActivity(intent);
//finish();
}
};
button.setOnClickListener(listener);
if(layoutRoot==null)
layoutRoot=(LinearLayout)findViewById(R.id.root);
if(textView1==null)
{
textView1=new MyTextView(this,"first view");
layoutRoot.addView(textView1);
}
Log.i(tag,"create one1");
;
}
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Log.i(tag,"one SaveInstanceState");
Parcelable savedState=textView1.onSaveInstanceState();
outState.putParcelable(kTextView1Name, savedState);
}
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
Log.i(tag,"one RestoreInstanceState");
SavedState0 savedState=savedInstanceState.getParcelable(kTextView1Name);
textView1.onRestoreInstanceState(savedState);
}
protected void onDestroy()
{
super.onDestroy();
Log.i(tag,"one Destroy");
}
}
文件2:Hello2.java
package com.teleca;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class Hello2 extends Activity {
String tag="hubin";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
Button button = (Button) findViewById(R.id.Button01);
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
Intent intent =new Intent(Hello2.this,Hello.class);
startActivity(intent);
}
};
button.setOnClickListener(listener);
}
protected void onSaveInstanceState(Bundle b)
{
Log.i(tag,"two SaveInstanceState");
}
protected void onDestroy()
{
super.onDestroy();
Log.i(tag,"two Destroy");
}
}
文件3:MyTextView.java
package com.teleca;
import java.util.HashMap;
import java.util.Set;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.Preference.BaseSavedState;
import android.util.Log;
import android.widget.TextView;
public class MyTextView extends TextView {
String tag="hubin";
int startPage;
HashMap checkedItemIds;
public MyTextView(Context context,String text) {
super(context);
// TODO Auto-generated constructor stub
Log.i(tag,"create TextView "+text);
this.setText(text);
startPage=(int)System.currentTimeMillis();
checkedItemIds=new HashMap();
checkedItemIds.put((long)startPage+1, true);
checkedItemIds.put((long)startPage+2, true);
checkedItemIds.put((long)startPage+3, true);
}
public Parcelable onSaveInstanceState()
{
Parcelable superState = super.onSaveInstanceState();
Log.i(tag,"onSave in TextView");
Log.i(tag,"save startPage:"+startPage);
Set set=checkedItemIds.keySet();
Object keys[]=set.toArray();
for(int i=0;i
{
Log.i(tag,"i:"+Long.parseLong(""+keys));
}
return new SavedState0(superState,startPage,checkedItemIds);
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState0 ss = (SavedState0) state;
Log.i(tag, "onRestoreInstanceState");
super.onRestoreInstanceState(ss.getSuperState());
startPage = ss.startPage;
checkedItemIds.clear();
checkedItemIds.putAll(ss.checkedItemIds);
Log.i(tag,"restore startPage:"+startPage);
Set set=checkedItemIds.keySet();
Object keys[]=(Long[])set.toArray();
for(int i=0;i
{
Log.i(tag,"i:"+Long.parseLong(""+keys));
}
}
}
class SavedState0 extends BaseSavedState {
int startPage;
HashMap checkedItemIds;
SavedState0(Parcelable superState, int startPage,HashMap checkedItemIds) {
super(superState);
this.startPage = startPage;
this.checkedItemIds = checkedItemIds;
}
private SavedState0(Parcel in) {
super(in);
startPage = in.readInt();
checkedItemIds = in.readHashMap(null);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(startPage);
out.writeMap(checkedItemIds);
}
@Override
public String toString() {
return "Text View SavedState{"
+ Integer.toHexString(System.identityHashCode(this)) + "}";
}
/*
* Interface that must be implemented and provided as a public CREATOR field
* that generates instances of your Parcelable class from a Parcel.
*/
/*
* Interface for classes whose instances can be written to and restored from a Parcel.
* Classes implementing the Parcelable interface must also have a static field called CREATOR,
* which is an object implementing the Parcelable.Creator interface.
*/
public static final Parcelable.Creator<SavedState0> CREATOR
= new Parcelable.Creator<SavedState0>() {
public SavedState0 createFromParcel(Parcel in) {
return new SavedState0(in);
}
public SavedState0[] newArray(int size) {
return new SavedState0[size];
}
};
}
注意1:当我们构造一个Parcelable的子类一定要定义public static final Parcelable.Creator CREATOR。
它用于从一个流创建Parcelable对象。注意是个具体的Parcelable对象。比如这里就是BaseSavedState对象。
对于Parcelable对象和流的转化机制(该示例的桥是Bundle),我想有两种可能:
A:在把Parcelable对象转为流的时候,除了Parcel的数据(通过方法writeToParcel得到),
还把Parcelable对象的构造器CREATOR的信息写到了流中。在读的时候,
就可以通过在流中读得关于CREATOR的信息找到Parcelable对象构造器CREATOR以便创建Parcelable对象(这里是BaseSavedState)
至于在写数据时,系统如何找到CREATOR,我想既然知道一个对象,那么虚拟机当然可以找他属于哪个类。
找到了属于哪个类,就可以找到CREATOR变量。当然也可能是通过一个对象的成员变量表直接找到CREATOR变量的。
B:在把Parcelable对象转为流的时候,除了Parcel的数据(通过方法writeToParcel得到),
还把Parcelable对象所属类的信息写到了流中。在读的时候,
就可以通过在流中读得关于Parcelable对象所属类的信息,找到Parcelable对象所属的类,
然后通过该类找到构造器CREATOR以便创建Parcelable对象(这里是BaseSavedState)