バンドルを介してオブジェクトを送信する方法


119

バンドルを介して処理の大部分を行うクラスへの参照を渡す必要があります。

問題は、インテントやコンテキストとは関係がなく、大量の非プリミティブオブジェクトがあることです。クラスをparcelable / serializableにパッケージ化してに渡すにはどうすればよいstartActivityForResultですか?


2
「バンドルを介して処理の大部分を行うクラスへの参照を渡す必要があります」-なぜですか?
CommonsWare 2010年

1
私はオブジェクト(DataManager)を持っています。それはサーバーを処理し、いくつかのGUIのいくつかのバックエンドを実行します。新しい接続が確立されたときはいつでも、ユーザーがListViewにすべてのアクティブな接続を一覧表示する新しいアクティビティを開始して、ユーザーに1つを選択できるようにしてください。結果のデータは、新しいGUIに関連付けられます。これは本当にバックエンドのスキンチョーサーです。
ahodder 2010年

3
複数のアクティビティでオブジェクトの同じインスタンスを処理している場合は、シングルトンパターンを検討することをお勧めします。ここに良いチュートリアルがあります
sotrh 2014

回答:


55

CommonsWareの重要な「なぜ」という質問だけでなく、「何をするのか」という質問にも答える必要があります。合格していますか?

実際には、バンドルを通過できるのはプレーンデータのみです。それ以外はすべて、そのデータの意味または参照先の解釈に基づいています。文字通りオブジェクトを渡すことはできませんが、できることは次の3つのうちの1つです。

1)オブジェクトを構成データに分解できます。もう一方の端に同じ種類のオブジェクトの知識がある場合、シリアル化されたデータからクローンを組み立てることができます。これが、一般的なタイプのほとんどがバンドルを通過する方法です。

2)不透明なハンドルを渡すことができます。同じコンテキスト内でそれを渡す場合(理由を尋ねる人もいるかもしれませんが)、それを呼び出しまたは逆参照できるハンドルになります。しかし、それをBinderを介して別のコンテキストに渡すと、そのリテラル値は任意の数になります(実際、これらの任意の数は起動から順番にカウントされます)。何もすることはできませんが、それを元のコンテキストに戻し、Binderがそれを元のハンドルに変換して再び使用できるようになるまで、それを追跡します。

3)ファイル記述子や特定のos /プラットフォームオブジェクトへの参照などのマジックハン​​ドルを渡すことができます。正しいフラグを設定すると、バインダーは実際に使用できる受信者の同じリソースを指すクローンを作成します。もう一方の端。しかし、これはごく少数のタイプのオブジェクトに対してのみ機能します。

ほとんどの場合、クラスを渡して、もう一方の端で追跡し、後でそれを返せるようにするか、シリアル化された構成データからクローンを作成できるコンテキストに渡すか、またはうまくいかないことをしようとしていて、アプローチ全体を再考する必要があります。


1
ツアー返信ありがとうございます。あなたの権利、私がする必要があるのは、オブジェクトのリストの参照を新しいアクティビティに渡すだけです。新しいアクティビティはリストからデータを取得し、選択可能なリストビューを表示します。onSelect、アクティビティはホストアクティビティに結果(クリックオブジェクトに関連する一部のデータ)を返します。私が正しく理解していれば、オプション2がこれを最も適切に処理すると思います。この不透明なハンドルを取得するにはどうすればよいですか?
ahodder 2010年

他のアクティビティでは、不透明オブジェクトからデータを抽出して表示することはできません。おそらくあなたがしたいことは、表示される情報のコピーを含むサポートされているタイプのいくつかのサロゲートオブジェクトを作成して渡してください。
Chris Stratton

158

Gsonを使用してオブジェクトをJSONObjectに変換し、バンドルで渡すこともできます。私にとっては、これを行うために見つけた最もエレガントな方法でした。パフォーマンスへの影響をテストしていません。

初期活動中

Intent activity = new Intent(MyActivity.this,NextActivity.class);
activity.putExtra("myObject", new Gson().toJson(myobject));
startActivity(activity);

次のアクティビティで

String jsonMyObject;
Bundle extras = getIntent().getExtras();
if (extras != null) {
   jsonMyObject = extras.getString("myObject");
}
MyObject myObject = new Gson().fromJson(jsonMyObject, MyObject.class);

3
アクティビティ間でのやり取りの問題であるため、アプリの全体的なパフォーマンスに大きな影響を与えるほど頻繁には発生しません。とは言っても、ソケット接続や他の同様のクラスがあるように聞こえるので、元の投稿のDataManagerをシリアル化することはうまくいかないと思います。
britzl 2013

4
また、GoogleはSerializeの代わりにこのソリューションを提案しています。このドキュメントページ
TechNyquist

3
警告の言葉として、私はしばらくこのテクニックに従いましたが、文字列として渡すことができるものにはメモリ制限があるため、データが大きすぎないことを確認してください。
ジドゥバ2015

プロジェクトにGsonサポートを追加する方法については、blog.madadipouya.com / 2015/09/21 /…をご覧ください。
geekQ 2016

スマートなソリューション、あなたに嫌われています!
Rohit Mandiwal 2016

20

Parcelableインタフェースは意図してオブジェクトを渡すための良い方法です。

カスタムオブジェクトをParcelableにするにはどうすればよいですか?Parcelableの使用方法についてはかなり良い答えです

公式のGoogleドキュメントにも例が含まれています


1
または、シリアル化も可能です。
ジェフリーブラットマン2013

1
しかし、パフォーマンスが大幅に10倍低下します!! このベンチマークを確認してください:developerphil.com/parcelable-vs-serializable
saiyancoder 2014年

2
+1 @Matiのコメント。ただし、1つのオブジェクトに適用されたときにコンテキストを10倍にするのは1ミリ秒に相当します。したがって、おそらくそれは思ったほど悪くはありません。
pinoyyid 2014年

1
同意します。問題は、コレクションを処理するときです。これは、Rest APIからリソースを取得する場合の非常に一般的な使用例です。しかし、単一のオブジェクトについては、悪名高いものであってはなりません。とにかく、すべてのボイラープレートコードが邪魔になっている場合は、それを生成するこのライブラリを試すことができます:github.com/johncarl81/parceler。本当に素晴らしいアプローチです!
saiyancoder 2014年

リンク切れ:404(見つかりません)
Gallal

14

グローバルなアプリケーション状態を使用できます。

更新:

これをカスタマイズしてAndroidManifest.xmlに追加します。

<application android:label="@string/app_name" android:debuggable="true" android:name=".CustomApplication"

そして、あなたのプロジェクトに次のようなクラスがあります:

package com.example;

import android.app.Application;

public class CustomApplication extends Application {
    public int someVariable = -1;
}

また、「任意のアクティビティまたはサービスからgetApplication()を介してアクセスできる」ため、次のように使用します。

CustomApplication application = (CustomApplication)getApplication();
application.someVariable = 123; 

お役に立てば幸いです。


1
返信ありがとうございます。
ahodder 2010年

私はあなたがアプリケーションをサブクラス化し、好きなものを保存できると信じています。必要なxmlの変更は、上記のリンクに記載されています。
Mark Storer、2010年

9
一般的な設計の原則として、本当に必要な場合を除いて、グローバルを回避することをお勧めします。この場合、良い代替案があります。
dhaag23

わかりました、私はあなたが言っていることを理解していると思います。Applicationを拡張して、渡す必要のあるオブジェクトを保持する変数をスローするだけです。リファレンスページを確認しましたが、必要なxmlの変更が表示されませんでした。
ahodder 2010年

これも答えとして書きたかった。これは間違いなくそれを行う方法の1つです。ただし、これらのオブジェクトは、デリファレンスしない限り(またはアプリコンテキストが破棄されない限り)メモリに残り、不要な場合は領域を占有する可能性があることに注意してください。
IgorČordaš2014年

12

また、あなたのオブジェクトを作ることができるシリアライズおよびバンドルの使用getSerializableputSerializable方法を。


1
私はそれを試しました、そしてそれが実際的でないであろうとすぐにわかりました。渡されたクラス(スレッド)に格納されているオブジェクトのほとんどはシリアル化可能ではないと思います。:)ありがとう。
ahodder

10

可能な解決策:

Bundle bundle = new Bundle();
bundle.putSerializable("key", new CustomObject());

クラスCustomObject:

class CustomObject implements Serializable{
 private SubCustomObject1 sc1;
 private SubCustomObject2 sc2;
}

サブカスタムオブジェクト:

class SubCustomObject1 implements Serializable{ }

class SubCustomObject2  implements Serializable{ }

7

バンドルを介してオブジェクトを送信するもう1つの方法は、サンプルコードを使用することbundle.putByteArray
です。

public class DataBean implements Serializable {
private Date currentTime;

public setDate() {
    currentTime = Calendar.getInstance().getTime();
 }

public Date getCurrentTime() {
    return currentTime;
 }
}

DataBeanのオブジェクトをバンドルに配置します。

class FirstClass{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Your code...

//When you want to start new Activity...
Intent dataIntent =new Intent(FirstClass.this, SecondClass.class);
            Bundle dataBundle=new Bundle();
            DataBean dataObj=new DataBean();
            dataObj.setDate();
            try {
                dataBundle.putByteArray("Obj_byte_array", object2Bytes(dataObj));

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();

            }

            dataIntent.putExtras(dataBundle);

            startActivity(dataIntent);
}

オブジェクトをバイト配列に変換する

/**
 * Converting objects to byte arrays
 */
static public byte[] object2Bytes( Object o ) throws IOException {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream( baos );
      oos.writeObject( o );
      return baos.toByteArray();
    }

バンドルからオブジェクトを取得します。

class SecondClass{
DataBean dataBean;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Your code...

//Get Info from Bundle...
    Bundle infoBundle=getIntent().getExtras();
    try {
        dataBean = (DataBean)bytes2Object(infoBundle.getByteArray("Obj_byte_array"));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

バイト配列からオブジェクトを取得するメソッド:

/**
 * Converting byte arrays to objects
 */
static public Object bytes2Object( byte raw[] )
        throws IOException, ClassNotFoundException {
      ByteArrayInputStream bais = new ByteArrayInputStream( raw );
      ObjectInputStream ois = new ObjectInputStream( bais );
      Object o = ois.readObject();
      return o;
    }

これが他の仲間に役立つことを願っています。


これは、コードを見るとスムーズで簡単に見えます。しかし、私はSDKがオブジェクトを渡すためにこのようなものを提供しない理由についてもっと何かがあると感じています。このソリューションについてもう少し教えていただけますか?
Mario Lenci 2013

3
そのすべてのコードはまったく必要ありません!bundle.putSerializable(objectImplementingSerializable)を使用してください-これは、ここで再度再実装しているものの下にあります...
Risadinha

3

1.非常に直接的で使いやすい例として、渡されるオブジェクトをSerializableに実装します。

class Object implements Serializable{
    String firstName;
   String lastName;
}

2.オブジェクトをバンドルで渡す

Bundle bundle = new Bundle();
Object Object = new Object();
bundle.putSerializable("object", object);

3.バンドルから渡されたオブジェクトをSerializableとして取得し、オブジェクトにキャストします。

Object object = (Object) getArguments().getSerializable("object");

0

これは私自身の質問にはかなり遅れた答えですが、注目を集め続けているので、私はそれに対処する必要があると感じています。これらの答えのほとんどは正しく、仕事を完全に処理します。ただし、アプリケーションのニーズによって異なります。この回答は、この問題の2つの解決策を説明するために使用されます。

応用

1つ目はアプリケーションです。ここで最もよく回答されています。アプリケーションは、コンテキストへの参照が必要なエンティティを配置するのに適したオブジェクトです。`ServerSocket`には間違いなくコンテキストが必要です(ファイルI / Oまたは単純な` ListAdapter`の更新の場合)。私は個人的に、このルートを好みます。私はアプリケーションが好きです。これらは、コンテキストを取得するのに役立ちます(静的にすることができ、メモリリークを引き起こす可能性がないため)。シンプルなライフサイクルがあります。

サービス

2番目 のサービスです。実際、サービスは、サービスが実行するように設計されているため、私の問題にとってより良い選択です。
サービスは、長時間実行される操作を実行できるアプリケーションコンポーネントです。
背景とユーザーインターフェイスを提供しません。
サービスは、制御が容易な、より明確なライフサイクルを持つという点で優れています。さらに、必要に応じて、サービスをアプリケーションの外部で(つまり、起動時に)実行できます。これは、一部のアプリまたは単なるきちんとした機能に必要な場合があります。

これも完全な説明ではありませんでしたが、さらに調査したい人のためにドキュメントへのリンクを残しました。全体としてServiceは、必要なインスタンスの方が優れています。SPPデバイスに対してServerSocketを実行します。


0

Dateオブジェクトを渡す方法を探しているときに、この質問に遭遇しました。私の場合、回答の中で示唆されているように、Bundle.putSerializable()を使用しましたが、元の投稿で説明されているDataManagerのように複雑なものには機能しません。

上記のDataManagerをアプリケーションに配置するか、シングルトンにするのと非常によく似た結果が得られるという私の提案は、依存性注入を使用してDataManagerをシングルトンスコープにバインドし、必要な場所にDataManagerを注入することです。テスト容易性が向上するだけでなく、すべてのボイラープレート「クラスとアクティビティ間の依存関係を渡す」コードがなくても、よりクリーンなコードが得られます。(Robo)Guiceは非常に扱いやすく、新しいDaggerフレームワークも有望に見えます。


1
さて、日付のようなもので、あなたはちょうど長い値を渡すことができます。しかし、残りはいいですね。ありがとう。
ahodder

0

バンドルを使用してオブジェクトを渡す別の簡単な方法:

  • クラスオブジェクトで、静的リストまたはキーを持つ別のデータ構造を作成します
  • オブジェクトを作成するときは、キー(つまり、オブジェクトが作成されたときの長いタイムスタンプ)とともにリスト/データ構造に配置します。
  • リストからオブジェクトを取得するためのメソッドstatic getObject(long key)を作成します
  • バンドルではキーを渡すので、後でコードの別のポイントからオブジェクトを取得できます
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.