Parcelableを使ってみる
今回はParcelableを使用してみようと思います
Parcelableとは
あるclassのInstanceをParcelに保存したり、または、復元したりするために実装するInterface(原文ここ)。Orientation変更したりするとSystemによりActivityがonDestroy()まで呼ばれ、再度、Activityの生成Processが実行されるので、Orientation変更前の状態を保持したい場合にそのinstanceのclassにParcelable interfaceを実装する感じですね
実装の要点をまとめます
1. Parcelable interfaceを実装する
public class ParcelableData implements Parcelable{ @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { } } }
2. Parcelable#writeToParcel()をoverrideし、引数に渡されるParcel objectに保存したいfieldを書き込む
@Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mString); dest.writeInt(mInt); dest.writeBooleanArray(mBooleanArray); dest.writeTypedList(mAnotherParcelableDataList); }
3. Parcelable.Createrを実装する
public static final Parcelable.Creator<ParcelableData> CREATOR = new Parcelable.Creator<ParcelableData>() { @Override public ParcelableData createFromParcel(Parcel in) { return new ParcelableData(in); } @Override public ParcelableData[] newArray(int size) { return new ParcelableData[size]; } }; }
4. Parcelable.Creater#createFromParcel()で返すobejctを生成するためのprivate constructor内で引数で渡されるParcel objectからfieldの値を復元
private ParcelableData(Parcel in) {
mString = in.readString();
mInt = in.readInt();
in.readBooleanArray(mBooleanArray);
in.readTypedList(mAnotherParcelableDataList, AnotherParcelableData.CREATOR);
}
5. Activity#onSaveInstanceState()内で引数に渡されるBundle objectにParcelable objectを保存する
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_PARCELABLE, mData); }
6. Activity#onCreate()内で引数に渡されるBundle objectからParcelable objectを復元する
@Override public void onCreate(Bundle savedInstanceState) { if(savedInstanceState != null){ mData = savedInstanceState.getParcelable(KEY_PARCELABLE); }else{ mData = createParcelableData(); } }
気付いた点をまとめます
- BooleanはArrayでしか保存出来ない
それでは実装です
Activity
package com.android.practice.parcelable; import java.util.ArrayList; import java.util.List; import com.android.practice.parcelable.ParcelableData.AnotherParcelableData; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MyActivity extends Activity { private static final String TAG = "MyActivity"; private static final String KEY_PARCELABLE = "key_parcelable"; private static final String STRING = "String"; private static final int INT = 1; private static final boolean BOOLEAN = false; private static final String ANOTHER_STRING = "Another String"; private static final String CHANGED_STRING = "Changed String"; private static final int CHANGED_INT = 2; private static final boolean CHANGED_BOOLEAN = true; private static final String CHANGED_ANOTHER_STRING = "Changed Another String"; private ParcelableData mData; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //Activity#onCreate()内で引数に渡されるBundle objectからParcelable objectを復元する if(savedInstanceState != null){ mData = savedInstanceState.getParcelable(KEY_PARCELABLE); }else{ mData = createParcelableData(); } Button changeButton = (Button)findViewById(R.id.change_button); changeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mData.setString(CHANGED_STRING); mData.setInt(CHANGED_INT); mData.setBoolean(CHANGED_BOOLEAN); mData.getAnotherParcelableDataList().get(0).setString(CHANGED_ANOTHER_STRING); setUpTextViews(); } }); setUpTextViews(); } @Override protected void onStart() { Log.d(TAG, "onStart"); super.onStart(); } @Override protected void onResume() { Log.d(TAG, "onResume"); super.onResume(); } //Activity#onSaveInstanceState()内で引数に渡されるBundle objectにParcelable objectを保存する @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_PARCELABLE, mData); } @Override protected void onPause() { Log.d(TAG, "onPause"); super.onPause(); } @Override protected void onStop() { Log.d(TAG, "onStop"); super.onStop(); } @Override protected void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } private ParcelableData createParcelableData(){ List<AnotherParcelableData> anotherDataList = new ArrayList<AnotherParcelableData>(); anotherDataList.add(new AnotherParcelableData(ANOTHER_STRING)); return new ParcelableData(STRING, INT, BOOLEAN, anotherDataList); } private void setUpTextViews(){ ((TextView)findViewById(R.id.string_text)).setText(mData.getString()); ((TextView)findViewById(R.id.int_text)).setText(String.valueOf(mData.getInt())); ((TextView)findViewById(R.id.boolean_text)).setText(String.valueOf(mData.getBoolean())); ((TextView)findViewById(R.id.another_string_text)).setText(String.valueOf(mData.getAnotherParcelableDataList().get(0).getString())); } }
Parcelableを実装したclass
package com.android.practice.parcelable; import java.util.List; import android.os.Parcel; import android.os.Parcelable; //Parcelable interfaceを実装する public class ParcelableData implements Parcelable{ private static final String TAG = "ParcelableData"; private String mString; private int mInt; private boolean[] mBooleanArray = new boolean[1]; private List<AnotherParcelableData> mAnotherParcelableDataList; public ParcelableData(){ } public ParcelableData(String string, int i, boolean bool, List<AnotherParcelableData> anotherParcelableDataList){ mString = string; mInt = i; mBooleanArray[0] = bool; mAnotherParcelableDataList = anotherParcelableDataList; } public String getString(){ return mString; } public void setString(String string){ mString = string; } public int getInt(){ return mInt; } public void setInt(int i){ mInt = i; } public boolean getBoolean(){ return mBooleanArray[0]; } public void setBoolean(boolean bool){ mBooleanArray[0] = bool; } public List<AnotherParcelableData> getAnotherParcelableDataList(){ return mAnotherParcelableDataList; } public void setAnotherParcelableDataList(List<AnotherParcelableData> anotherParelableDataList){ mAnotherParcelableDataList = anotherParelableDataList; } @Override public int describeContents() { return 0; } //Parcelable#writeToParcel()をoverrideし、引数に渡されるParcel objectに保存したいfieldを書き込む @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mString); dest.writeInt(mInt); //BooleanはArrayでしか保存出来ない dest.writeBooleanArray(mBooleanArray); dest.writeTypedList(mAnotherParcelableDataList); } //Parcelable.Createrを実装する public static final Parcelable.Creator<ParcelableData> CREATOR = new Parcelable.Creator<ParcelableData>() { @Override public ParcelableData createFromParcel(Parcel in) { return new ParcelableData(in); } @Override public ParcelableData[] newArray(int size) { return new ParcelableData[size]; } }; //Parcelable.Creater#createFromParcel()で返すobejctを生成するためのprivate constructor内で //引数で渡されるParcel objectからfieldの値を復元 private ParcelableData(Parcel in) { mString = in.readString(); mInt = in.readInt(); in.readBooleanArray(mBooleanArray); in.readTypedList(mAnotherParcelableDataList, AnotherParcelableData.CREATOR); } public static class AnotherParcelableData implements Parcelable{ private String mString; public AnotherParcelableData(){ } public AnotherParcelableData(String string){ mString = string; } public String getString(){ return mString; } public void setString(String string){ mString = string; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mString); } public static final Parcelable.Creator<AnotherParcelableData> CREATOR = new Parcelable.Creator<AnotherParcelableData>() { public AnotherParcelableData createFromParcel(Parcel in) { return new AnotherParcelableData(in); } public AnotherParcelableData[] newArray(int size) { return new AnotherParcelableData[size]; } }; private AnotherParcelableData(Parcel in) { mString = in.readString(); } } }
と、こんな感じです。
ちなみに、Manifest fileに下記の様にandroid:configChange="orientation"を指定すればorientation変更の際にActivityの再起動を避ける事が出来ます
<activity android:name="MyActivity" android:configChanges="keyboardHidden|orientation">