web-dev-qa-db-ja.com

アクティビティ間でデータを共有するための最善の方法は何ですか?

私はアプリ全体で使用される主な活動であり、それはいくつかの変数を持っている一つの活動を持っています。私は最初の活動からのデータを使用できるようにしたいと思う他の2つの活動があります。今私は私がこのようなことをすることができることを知っている:

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

しかし、私はたくさんの変数を共有したいと思っています、そして、いくつかはかなり大きいかもしれないので、私は上記のようにそれらのコピーを作成したくありません。

Getメソッドとsetメソッドを使わずに変数を直接取得して変更する方法はありますか?私はこれがAndroidでのパフォーマンスには推奨されないと言っているGoogleのdevサイトの記事を読んだのを覚えています。

227
Crazyfool

ここで これを達成するための最も一般的な方法 のコンパイル:

  • インテント内にデータを送信する
  • 静的フィールド
  • WeakReferencesのハッシュマップ
  • 永続オブジェクト(sqlite、共有設定、ファイルなど)

TL; DR:データを共有するには2つの方法があります。インテントのエクストラでデータを渡すこと、または他の場所に保存することです。データがプリミティブ、文字列、またはユーザー定義オブジェクトの場合は、インテントエクストラの一部として送信します(ユーザー定義オブジェクトはParcelableを実装する必要があります)。複雑なオブジェクトを渡す場合、インスタンスを別の場所のシングルトンに保存し、起動したアクティビティからそれらにアクセスします。

どのようにそしてなぜそれぞれのアプローチを実行するべきかに関するいくつかの例:

インテント内でデータを送信する

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);

第二の活動について:

Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");

このメソッドを使用してくださいあなたがプリミティブデータまたは文字列を渡す場合Serializableを実装するオブジェクトを渡すこともできます。

魅力的ですが、Serializableを使う前に二度考えてください。エラーが発生しやすく、恐ろしいほど遅くなります。そのため一般的には、可能ならばSerializableから離れてとしてください。複雑なユーザ定義オブジェクトを渡したい場合は、Parcelableインタフェースを見てください。実装するのは難しいですが、Serializableと比べてかなりスピードが上がります。

ディスクに永続化せずにデータを共有する

ほとんどの場合、両方のアクティビティは同じプロセスで実行されるため、データをメモリに保存することでアクティビティ間でデータを共有することができます。

注:時々、ユーザーがあなたの活動をやめることなく去るとき、Androidはあなたのアプリケーションを殺すことを決定するかもしれません。そのようなシナリオで、私はAndroidがアプリが殺される前に提供された意図を使って最後の活動を始めようと試みるケースを経験しました。この場合、シングルトン(yoursまたはApplication)に保存されていたデータはなくなり、悪いことが起こる可能性があります。このような場合を回避するには、オブジェクトをディスクに永続化するか、データを使用する前にデータをチェックして有効性を確認します。

シングルトンクラスを使う

データを保持するクラスがあります。

public class DataHolder {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}

  private static final DataHolder holder = new DataHolder();
  public static DataHolder getInstance() {return holder;}
}

立ち上げられた活動から:

String data = DataHolder.getInstance().getData();

アプリケーションシングルトンを使用する

アプリケーションシングルトンは、アプリの起動時に作成されるAndroid.app.Applicationのインスタンスです。 Applicationを拡張することでカスタムのものを提供できます。

import Android.app.Application;
public class MyApplication extends Application {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}
}

アクティビティを開始する前に

MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);

それから、立ち上げられた活動から:

MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();

静的フィールド

考え方は基本的にシングルトンと同じですが、この場合はデータへの静的アクセスを提供します。

public class DataHolder {
  private static String data;
  public static String getData() {return data;}
  public static String setData(String data) {DataHolder.data = data;}
}

立ち上げられた活動から:

String data = DataHolder.getData();

WeakReferencesのハッシュマップ

同じ考え方ですが、ガベージコレクタが参照されていないオブジェクトを削除できるようにします(ユーザーがアクティビティを終了したときなど)。

public class DataHolder {
  Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();

  void save(String id, Object object) {
    data.put(id, new WeakReference<Object>(object));
  }

  Object retrieve(String id) {
    WeakReference<Object> objectWeakReference = data.get(id);
    return objectWeakReference.get();
  }
}

アクティビティを開始する前に

DataHolder.getInstance().save(someId, someObject);

立ち上げられた活動から:

DataHolder.getInstance().retrieve(someId);

インテントのエキストラを使用してオブジェクトIDを渡す必要があるかもしれません。それはすべてあなたの特定の問題によります。

オブジェクトをディスクに永続化

アイデアは他のアクティビティを起動する前にデータをディスクに保存することです。

長所:他の場所からアクティビティを起動することができます。データが既に保持されている場合は、正常に機能するはずです。

デメリット:面倒で実装に時間がかかります。より多くのコードを必要とし、それゆえバグを引き起こす可能性がより高い。また遅くなります。

オブジェクトを永続化する方法のいくつかは次のとおりです。

458
Cristian

あなたが使用できるもの:

  1. アクティビティ間でデータを受け渡す(クリスチャンが言ったように)
  2. たくさんの静的変数を持つクラスを使う(つまり、クラスのインスタンスやgetter/setterを使わずにそれらを呼び出すことができる)
  3. データベースを使う
  4. 共有設定

あなたが選ぶものはあなたのニーズによって異なります。あなたが「たくさん」持っているとき、おそらくあなたは複数の方法を使うでしょう

22
WarrenFaith

グーグルがあなたにするように命令することをしなさい!ここ: http://developer.Android.com/resources/faq/framework.html#

  • プリミティブデータ型
  • 非永続オブジェクト
  • シングルトンクラス - 私のお気に入り:D
  • パブリックスタティックフィールド/メソッド
  • オブジェクトへの弱い参照のハッシュマップ
  • 永続オブジェクト(アプリケーション設定、ファイル、コンテンツプロバイダ、SQLite DB)
16

「しかし、私はたくさんの変数を共有したいと思っています、そして、いくらか大きいかもしれないので、私は上記のようなそれらのコピーを作成したくないです。」

これはコピーを作成しません(特にStringを使用しますが、オブジェクトではなく参照の値でオブジェクトが渡されます)。使用するのは問題ありません - それらは一般的でよく理解されているので間違いなく他の方法よりも使用する方が良いです)。ゲッターやセッターを使用しないなどの古い「パフォーマンス神話」には、まだある程度の価値がありますが、 ドキュメントでも更新されています

しかし、そうしたくない場合は、GlobalStateで変数をpublicまたはprotectedにして直接アクセスすることもできます。そして、 アプリケーションオブジェクトJavaDocが示す として静的なシングルトンを作ることができます。

通常、Applicationをサブクラス化する必要はありません。ほとんどの場合、スタティックシングルトンはより機能的な方法で同じ機能を提供できます。シングルトンがグローバルコンテキストを必要とする場合(たとえば、ブロードキャストレシーバを登録する場合)、それを取得する関数には、シングルトンを最初に構築するときに内部的にContext.getApplicationContext()を使用するContextを指定できます。

インテントデータを使用することは、他の回答としてデータを渡すもう1つの方法ですが、通常は小さいデータと単純な型に使用されます。もっと大きい/もっと複雑なデータを渡すこともできますが、静的なシングロンを使うよりも複雑です。ただし、 Application オブジェクトは、Androidアプリケーションコンポーネント間でより大きく/より複雑な非永続データを共有するための私の個人的なお気に入りです(Androidアプリで明確に定義されたライフサイクルがあるため)。

また、他の人が指摘したように、データが非常に複雑になり、永続的である必要がある場合、SQLiteまたはファイルシステムも使用できます。

14
Charlie Collins

Application クラスを拡張してそこに必要なオブジェクトをタグ付けすると、それらはアプリケーション内のどこでも使用可能になります。

7
Jimmy

アクティビティ間でデータを共有するための新しいより良い方法があります。それは LiveData です。特にAndroid開発者のページからのこの引用に注意してください。

LiveDataオブジェクトがライフサイクルに対応しているという事実は、それらを複数のアクティビティ、フラグメント、およびサービス間で共有できることを意味します。例を単純にするために、LiveDataクラスをシングルトンとして実装できます。

これが意味することは巨大です - どんなモデルデータもLiveDataラッパーの中の共通のシングルトンクラスで共有することができます。テスト容易のためにアクティビティからそれぞれのViewModelにインジェクトすることができます。また、メモリリークを防ぐために弱い参照を心配する必要はもうありません。

2
Amir Uval

活動間でデータを共有するにはさまざまな方法があります

1:Intentを使用して活動間でデータを受け渡す

Intent intent=new Intent(this, desirableActivity.class);
intent.putExtra("KEY", "Value");
startActivity(intent)

2:staticキーワードを使用して、変数をpublic staticとして定義し、プロジェクト内の任意の場所を使用します

      public static int sInitialValue=0;

classname.variableNameを使用してプロジェクト内の任意の場所で使用します。

3:データベースを使う

しかし、少し時間がかかるプロセスです。データを挿入するにはクエリを使用し、必要に応じてカーソルを使用してデータを繰り返す必要があります。しかし、キャッシュを消去しないとデータを失う可能性はありません。

4:共有設定を使う

データベースよりはるかに簡単です。ただし、ArrayList、List、およびcustomeオブジェクトを保存できないという制限があります。

5:Aplicationクラスにゲッターセッターを作成し、プロジェクト内の任意の場所にアクセスします。

      private String data;
      public String getData() {
          return data;
      }

      public void setData(String data) {
          this.data = data;
      }

ここで設定し、活動から取得します

         ((YourApplicationClass)getApplicationContext()).setData("abc"); 

         String data=((YourApplicationClass)getApplicationContext()).getData();  
2
vikas singh

上で説明した、および http://developer.Android.com/guide/faq/framework.html で説明されている、弱参照アプローチのハッシュマップを使用すると、私には問題があるようです。マップ値だけでなく、エントリー全体がどのように回収されますか?どの範囲に割り当てますか。フレームワークはアクティビティのライフサイクルを管理しているため、参加しているアクティビティの1つを所有していると、所有者がそのクライアントに先立って破棄されるとランタイムエラーが発生します。アプリケーションがそれを所有している場合、ハッシュマップが有効なキーと潜在的に無効化されて収集された弱い参照を持つエントリを保持しないようにするために、アクティビティはエントリを明示的に削除する必要があります。さらに、キーに対して返された値がnullの場合、クライアントは何をすべきでしょうか。

アプリケーションによって所有されているか、シングルトン内にあるWeakHashMapがより良い選択であるように私には思えます。マップ内の値はキーオブジェクトを介してアクセスされ、キーへの強力な参照が存在しない場合(つまり、すべてのアクティビティがそのキーを使って行われ、それがマップされるもの)、GCはマップエントリを再利用できます。

2
Mark Rosenberg

アクティビティー間でデータを共有する例 - ログイン後にEメールを渡す

「email」は、要求されているアクティビティの値を参照するために使用できる名前です。

1ログインページのコード

Intent openLoginActivity = new Intent(getBaseContext(), Home.class);
    openLoginActivity.putExtra("email", getEmail);

ホームページの2つのコード

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
1
jeff

私はいくつかのアイデアを持っていますが、それらがあなたが探しているものであるかどうか私は知りません。

すべてのデータを保持するサービスを使用してから、データの回収のために自分のアクティビティをサービスにバインドすることができます。

あるいは、データを直列化可能または構文解析可能にパッケージ化してそれらをバンドルに添付し、そのバンドルをアクティビティー間で渡します。

これはまったくあなたが探しているものではないかもしれませんが、あなたは一般的にSharedPreferencesまたは好みを使ってみることもできます。

どちらにしてもあなたが決めたことを私に知らせてください。

1
ahodder

インテントを使用してアクティビティ1からアクティビティ2を呼び出すとします。
intent.putExtra()でデータを渡すことができます。

参考のためにこれを持っていってください。 Intent.putExtraを使って配列を送る

それがあなたが望むものであることを願っています。

1
Manish Khot

前述の答えはすべて素晴らしいです...私はアクティビティを通じてデータを永続化することについてまだ誰も言及していないものを追加しています。関連するデータを永続化するには、組み込みのAndroid SQLiteデータベースを使用します。 databaseHelperをアプリケーション状態にして、アクティブ化の間中必要に応じて呼び出します。あるいは、ヘルパークラスを作成し、必要に応じてDB呼び出しを行います。検討のために別のレイヤーを追加するだけです。同様に..本当にただ好み

1
avatar

現在のアクティビティから他のアクティビティを呼び出すことを目的としている場合は、 Intents を使用してください。必要に応じてデータを共有するよりも、データを永続化することに重点が置かれない可能性があります。

ただし、これらの値を本当に保持する必要がある場合は、ローカルストレージ上の何らかの構造化テキストファイルまたはデータベースにそれらを保持することができます。プロパティファイル、XMLファイル、またはJSONファイルにデータを格納し、アクティビティの作成中に簡単に解析することができます。あなたがすべてのAndroidデバイス上でSQLiteを持っていることも忘れないでください、あなたはそれらをデータベーステーブルに保存することができます。 Mapを使用してキーと値のペアを格納し、そのマップをローカルストレージにシリアル化することもできますが、これは面倒すぎて単純なデータ構造には役立ちません。

1
Mike Yockey

そして、もしあなたがデータオブジェクトを操作したいのであれば、この二つは非常に重要な実装です:

直列化可能対Parcelable

  • シリアライズ可能は、ユーザーが自分の要件に従ってデータを整列化できないことを意味するマーカーインターフェイスです。そのため、オブジェクト実装時に直列化可能Javaは自動的に直列化します。
  • ParcelableはAndroid自身のシリアル化プロトコルです。 Parcelableでは、開発者は整列化と非整列化のためのカスタムコードを記述します。そのため、シリアル化と比較して不要なオブジェクトが少なくなります。
  • カスタム実装のため、ParcelableのパフォーマンスはSerializableと比較して非常に高いです。Androidでオブジェクトをシリアル化する場合はParcelable埋め込みを使用することを強くお勧めします。

public class User implements Parcelable

もっとチェックイン ここ

0
Diego Venâncio