私が理解しているように、Androidがシリアル化を実行する方法BundleにParcelable属しています。これは、たとえば、アクティビティ間でデータを渡す際に使用されます。Parcelableしかし、たとえば、ビジネスオブジェクトの状態を内部メモリに保存する場合に、従来のシリアル化の代わりに使用することに利点があるのではないかと思います。従来の方法よりも簡単ですか、それとも高速ですか?従来のシリアル化をどこで使用する必要があり、バンドルをどこで使用する方がよいですか?
9 に答える
「ProAndroid2」より
注:Parcelableを見ると質問が発生した可能性がありますが、Androidが組み込みのJavaシリアル化メカニズムを使用していないのはなぜですか?Androidチームは、Javaでのシリアル化が遅すぎて、Androidのプロセス間通信要件を満たすことができないという結論に達しました。そこで、チームはParcelableソリューションを構築しました。Parcelableアプローチでは、クラスのメンバーを明示的にシリアル化する必要がありますが、最終的には、オブジェクトのシリアル化がはるかに高速になります。
また、Androidには、データを別のプロセスに渡すことができる2つのメカニズムが用意されていることも理解してください。1つは、インテントを使用してバンドルをアクティビティに渡すことであり、2つ目は、Parcelableをサービスに渡すことです。これらの2つのメカニズムは互換性がなく、混同しないでください。つまり、Parcelableはアクティビティに渡されることを意図していません。アクティビティを開始してデータを渡す場合は、バンドルを使用します。Parcelableは、AIDL定義の一部としてのみ使用することを目的としています。
SerializableAndroidではコミカルに遅いです。実際、多くの場合、境界線は役に立たない。
ParcelParcelable素晴らしく高速ですが、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++;
}
}
}
つまり、ストレージの目的でシリアル化が必要であるが、Serializableインターフェイスによって発生するリフレクションの速度ペナルティを回避したい場合は、 Externalizableインターフェイスを使用して独自のシリアル化プロトコルを明示的に作成する必要があります。
適切に実装された場合、これはParcelableの速度と一致し、AndroidやJavaプラットフォームの異なるバージョン間の互換性も考慮します。
この記事でも問題が解決する可能性があります。
JavaのSerializableとExternalizableの違いは何ですか?
ちなみに、これは多くのベンチマークで最速のシリアル化手法でもあり、Kryo、Avro、Protocol Buffers、Jackson(json)を上回っています。
http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking
今日では、少なくとも自分の活動の間にそれを実行するときは、違いはそれほど目立たないようです。
このウェブサイトに示されているテストによると、Parcelableは最新のデバイス(nexus 10など)では約10倍高速であり、古いデバイス(desire Zなど)では約17倍高速です。
ですから、それが価値があるかどうかを決めるのはあなた次第です。
おそらく比較的小さくて単純なクラスの場合、Serializableは問題ありません。それ以外の場合は、Parcelableを使用する必要があります。
Parcelableは主に、データがParcelsとして渡されるBinderインフラストラクチャを使用するIPCに関連しています。
AndroidはすべてではないにしてもほとんどのIPCタスクをBinderに大きく依存しているため、必要に応じてオブジェクトを別のプロセスに渡すことができるため、ほとんどの場所、特にフレームワークにParcelableを実装することは理にかなっています。オブジェクトを「移動可能」にします。
ただし、シリアル化可能オブジェクトを広範囲に使用してオブジェクトの状態を保存し、それらをファイルシステムに保存するだけでよい、Android固有ではないビジネスレイヤーがある場合は、シリアル化可能で問題ないと思います。これにより、パーセル可能なボイラープレートコードを回避できます。
この記事に基づくと、http: //www.mooproductions.org/node/6?page= 5Parcelableの方が高速であるはずです。
記事で言及されていないのは、シリアル化可能なオブジェクトがリモートサービスのAIDLで機能するとは思わないということです。
GSON->JSON文字列へのシリアル化->JSON文字列からのオブジェクトの復元を使用します。
また、Parcelableは、ユーザーがwriteToParcel()をオーバーライドすることで各オブジェクトをパーセル化する機会を得るカスタム実装を提供しますが、データを渡す方法にはJAVAリフレクションAPIが含まれるため、シリアル化ではこのカスタム実装は行われません。

