私が理解しているように、Bundle
とParcelable
はAndroidがシリアル化を実行する方法に属します。たとえば、アクティビティ間でデータを渡す場合に使用されます。たとえば、ビジネスオブジェクトの状態を内部メモリに保存する場合に、従来のシリアル化の代わりにParcelable
を使用することに利点がある場合は、従来の方法よりも簡単ですか、それとも高速ですか?バンドルを使用するのに適した場所はどこですか?
「Pro Android 2」から
注:Parcelableを見ると質問がトリガーされる可能性があります。なぜAndroid組み込みのJavaシリアル化メカニズムを使用していないのですか?Androidチームは、Javaでのシリアル化はAndroidのプロセス間通信要件を満たすには遅すぎるという結論に達しました。したがって、チームはParcelableソリューションを構築しました。クラスのメンバーを明示的にシリアル化しますが、最終的にはオブジェクトのシリアル化がはるかに高速になります。
また、Androidは別のプロセスにデータを渡すことができる2つのメカニズムを提供します。1つ目はインテントを使用してバンドルをアクティビティに渡すことで、2つ目はParcelableをこれらの2つのメカニズムは互換性がなく、混同しないでください。つまり、Parcelableはアクティビティに渡されることを意図していません。アクティビティを開始してデータを渡す場合は、バンドルを使用します。 AIDL定義の一部としてのみ使用されます。
Serializable
はAndroidで滑comに遅いです。実際、多くの場合、境界線は役に立たない。
Parcel
とParcelable
は素晴らしく高速ですが、 ドキュメント は、ストレージの汎用シリアル化に使用してはいけないことを示しています。 Android(つまり、OSの更新により、依存しているアプリが破損する可能性があります)。
合理的な速度でストレージにデータをシリアル化する問題の最良の解決策は、独自にロールすることです。私は個人的に、Parcel
と同様のインターフェースを持ち、すべての標準タイプを非常に効率的にシリアル化できる独自のユーティリティクラスの1つを使用しています(タイプセーフティを犠牲にします)。以下はその短縮版です。
public interface Packageable {
public void readFromPackage(PackageInputStream in) throws IOException ;
public void writeToPackage(PackageOutputStream out) throws IOException ;
}
public final class PackageInputStream {
private DataInputStream input;
public PackageInputStream(InputStream in) {
input = new DataInputStream(new BufferedInputStream(in));
}
public void close() throws IOException {
if (input != null) {
input.close();
input = null;
}
}
// Primitives
public final int readInt() throws IOException {
return input.readInt();
}
public final long readLong() throws IOException {
return input.readLong();
}
public final long[] readLongArray() throws IOException {
int c = input.readInt();
if (c == -1) {
return null;
}
long[] a = new long[c];
for (int i=0 ; i<c ; i++) {
a[i] = input.readLong();
}
return a;
}
...
public final String readString() throws IOException {
return input.readUTF();
}
public final <T extends Packageable> ArrayList<T> readPackageableList(Class<T> clazz) throws IOException {
int N = readInt();
if (N == -1) {
return null;
}
ArrayList<T> list = new ArrayList<T>();
while (N>0) {
try {
T item = (T) clazz.newInstance();
item.readFromPackage(this);
list.add(item);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
N--;
}
return list;
}
}
public final class PackageOutputStream {
private DataOutputStream output;
public PackageOutputStream(OutputStream out) {
output = new DataOutputStream(new BufferedOutputStream(out));
}
public void close() throws IOException {
if (output != null) {
output.close();
output = null;
}
}
// Primitives
public final void writeInt(int val) throws IOException {
output.writeInt(val);
}
public final void writeLong(long val) throws IOException {
output.writeLong(val);
}
public final void writeLongArray(long[] val) throws IOException {
if (val == null) {
writeInt(-1);
return;
}
writeInt(val.length);
for (int i=0 ; i<val.length ; i++) {
output.writeLong(val[i]);
}
}
public final void writeFloat(float val) throws IOException {
output.writeFloat(val);
}
public final void writeDouble(double val) throws IOException {
output.writeDouble(val);
}
public final void writeString(String val) throws IOException {
if (val == null) {
output.writeUTF("");
return;
}
output.writeUTF(val);
}
public final <T extends Packageable> void writePackageableList(ArrayList<T> val) throws IOException {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
int i=0;
writeInt(N);
while (i < N) {
Packageable item = val.get(i);
item.writeToPackage(this);
i++;
}
}
}
少なくとも、自分のアクティビティ間で実行した場合を除いて、この違いはそれほど顕著ではないようです。
このWebサイト に示されているテストによると、Parcelableは最新のデバイス(nexus 10など)で約10倍、古いデバイス(desire Zなど)で約17倍高速です。
それが価値があるかどうかを決めるのはあなた次第です。
比較的小さく単純なクラスの場合はSerializableで十分ですが、残りの場合はParcelableを使用する必要があります
Parcelableは主に、データが Parcels として渡される Binder インフラストラクチャを使用してIPCに関連しています。
AndroidはすべてではないにしてもほとんどのIPCタスクをBinderに依存しているため、ほとんどの場所、特にフレームワークでParcelableを実装することは理にかなっています。必要に応じて別のプロセスに反対します。オブジェクトを「トランスポータブル」にします。
しかし、シリアライズ可能オブジェクトを広く使用してオブジェクトの状態を保存し、それらをファイルシステムに保存するだけでよい非Android固有のビジネスレイヤーがある場合、シリアライズ可能オブジェクトは問題ないと思います。 Parcelableボイラープレートコードを回避できます。
この記事に基づいて http://www.mooproductions.org/node/6?page=5 Parcelableはより高速になるはずです。
記事には記載されていませんが、シリアル化可能なオブジェクトがリモートサービスのAIDLで機能するとは考えていません。
GSON-> JSON文字列へのシリアル化-> JSON文字列からのオブジェクトの復元を使用します。
また、Parcelableは、ユーザーがwriteToParcel()をオーバーライドすることで各オブジェクトをパーセルする機会を得るカスタム実装を提供します。ただし、データを渡す方法にはJava reflection API 。