Parcelable と Bundle

Parcelable オブジェクトと Bundle オブジェクトは、IPC/Binder トランザクションやインテントを持つアクティビティ間など、プロセスの境界を越えて使用したり、構成変更の前後で一時的な状態を保存したりすることが想定されています。このページでは、Parcelable オブジェクトと Bundle オブジェクトの使用に関する推奨事項とベスト プラクティスについて説明します。

注: Parcel は汎用のシリアル化メカニズムではないため、Parcel データをディスクに保存したり、ネットワーク経由で送信したりしないでください。

アクティビティ間でデータを送信する

アプリが新しいアクティビティの開始時に startActivity(android.content.Intent) で使用する Intent オブジェクトを作成する場合、アプリは putExtra(java.lang.String, java.lang.String) メソッドを使用してパラメータを渡すことができます。

次のコード スニペットに、この処理を実行する方法の例を示します。

Kotlin

val intent = Intent(this, MyActivity::class.java).apply {
    putExtra("media_id", "a1b2c3")
    // ...
}
startActivity(intent)

Java

Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("media_id", "a1b2c3");
// ...
startActivity(intent);

OS は、インテントの基となる Bundle をパーセル化します。その後、OS は新しいアクティビティを作成し、データのパーセルを解除して、インテントを新しいアクティビティに渡します。

Bundle クラスを使用して、OS が認識しているプリミティブを Intent オブジェクトに設定することをおすすめします。Bundle クラスは、パーセルを使用したマーシャリングとマーシャリング解除用に高度に最適化されています。

場合によっては、アクティビティ間で複合オブジェクトや複雑なオブジェクトを送信するメカニズムが必要になることがあります。このような場合、カスタムクラスは Parcelable を実装し、適切な writeToParcel(android.os.Parcel, int) メソッドを提供する必要があります。また、Parcelable.Creator インターフェースを実装する CREATOR という null 以外のフィールドも提供する必要があります。その createFromParcel() メソッドは、Parcel を現在のオブジェクトに戻すために使用されます。詳細については、Parcelable オブジェクトのリファレンス ドキュメントをご覧ください。

インテントを介してデータを送信する場合は、データサイズを数 KB に制限するように注意する必要があります。送信するデータが多すぎると、システムが TransactionTooLargeException 例外をスローすることがあります。

プロセス間でデータを送信する

プロセス間でデータを送信する方法は、アクティビティ間で行う方法と似ています。ただし、プロセス間で送信する場合は、カスタム Parcelable を使用しないことをおすすめします。カスタム Parcelable オブジェクトをアプリ間で送信する場合、送信側アプリと受信側アプリの両方に、まったく同じバージョンのカスタムクラスが存在することを確認する必要があります。通常、これは両方のアプリで使用される共通ライブラリになります。アプリがカスタム Parcelable をシステムに送信しようとすると、システムが認識していないクラスをアンマーシャリングできないため、エラーが発生する可能性があります。

たとえば、アプリで AlarmManager クラスを使用してアラームを設定し、アラーム インテントでカスタム Parcelable を使用するとします。アラームが鳴ると、システムはインテントのエクストラの Bundle を変更して繰り返しカウントを追加します。この変更により、システムでエクストラからカスタム Parcelable が削除される可能性があります。このようにストリッピングを行うと、変更されたアラーム インテントを受け取る際に、アプリがクラッシュする可能性があります。これは、アプリが存在しない追加のデータの受信を想定しているためです。

Binder トランザクション バッファのサイズには制限があります(現在は 1 MB )。これは、プロセスで進行中のすべてのトランザクションによって共有されます。この制限はアクティビティ単位ではなくプロセスレベルで適用されるため、これらのトランザクションには、アプリ内のすべてのバインダー トランザクション(onSaveInstanceState、startActivity、システムとのすべてのやり取り)が含まれます。サイズの上限を超えると、TransactionTooLargeException がスローされます。

savedInstanceState の特定のケースでは、データ量を少なく抑える必要があります。システム プロセスは、ユーザーがそのアクティビティに戻れる限り(アクティビティのプロセスが強制終了された場合でも)提供されたデータを保持する必要があるためです。保存済み状態は 5 万データ未満に抑えることをおすすめします。

注: Android 7.0(API レベル 24)以降では、ランタイム例外として TransactionTooLargeException がスローされます。以前のバージョンの Android では、logcat に警告のみが表示されます。