web-dev-qa-db-ja.com

Android BroadcastReceiverまたは単純なコールバックメソッド?

私のプロジェクトでは、長時間実行中のスレッドからのコールバックとしてBroadcastReceiversを使用しています(たとえば、ダウンロードが完了したことをアクティビティに通知し、Worker Threadから応答データを送信して、アクティビティができるようにしますユーザーに適切なメッセージを表示します。 BroadcastReceiversを使用するには、ブロードキャストレシーバーを使用するたびに登録および登録解除するように注意する必要があります。また、このメソッドを使用してさまざまなアクション(ダウンロードなど)を行う場合は、特に送信するメッセージに注意する必要があります。 、WebService呼び出しなどを行います)。また、ブロードキャストの目的でカスタムオブジェクトを送信するには、オブジェクトをParcelableにする必要もあります。

このアプローチとは異なり、私が使用するメソッドよりも単純に見えるコールバックメソッドのアプローチも見ました。コールバックメソッドは、アプリメッセージングのBroadcastRecaiverと同じ効果を達成するために使用できるシンプルなインターフェイスメソッドの実装です。このアプローチは、複雑なオブジェクトを返すためにParcelable実装を必要とせず、BroadcastReceiverのようなキーを使用しません。悪い点は、コールする前にコールバックオブジェクトのnull値を確認する必要があることですコールバックメソッドと、UIスレッドの実装からコードを実行していることを確認して、エラーなしでUIを更新できるようにします。

わかりました、私が言うつもりのことを理解していただければ幸いです:)。

質問は、単一のアプリケーションの内部でのみ使用する場合、コールバックメソッドはBroadcastReceiverアプローチよりも優れている(軽量、クリーン、高速)と思いますか? (私はAndroid Serviceをバックグラウンドで使用していないことに注意してください。AsyncTaskThreadsのみ)

ありがとうございました!

55
Cata

これは非常に興味深い質問で、同じ問題に遭遇しました。私の意見では、両方のメカニズムを完全に使用することができ、使用する適切なアプローチはユースケースに依存します。決定する前に考慮すべきいくつかのポイントがあります。

コールバックメカニズムの使用にはいくつかの利点がありますが、制限もあります。

プロ

  • 実装は簡単で簡単です。
  • 相互に作用するコンポーネント間でタイプセーフが得られます。
  • 任意のオブジェクトを返すことができます。
  • 単体テストでモックコールバック(mockitoなどで生成されたもの)を挿入するだけでよいので、テストが簡単になります。

コントラ

  • UIを操作するには、メインスレッドに切り替える必要があります。
  • 1対1の関係しか持てません。 1対nの関係(オブザーバーパターン)は、さらなる作業なしでは実現できません。この場合、AndroidのObserver/Observableメカニズムを使用します。
  • すでに述べたように、コールバックがオプションの場合は、コールバック関数を呼び出す前に常にnullを確認する必要があります。
  • コンポーネントがさまざまなサービス関数を備えた一種のサービスAPIを提供する必要があり、少数の汎用コールバック関数のみを含むコールバックインターフェイスを使用したくない場合は、各サービス関数に特別なコールバックインターフェイスを提供するか、または多くのコールバック関数を備えた単一のコールバックインターフェイスを提供します。後者の場合、APIへのサービス呼び出しに使用されるすべてのコールバッククライアントは、完全なコールバックインターフェイスを実装する必要がありますが、メソッド本体の大部分は空になります。空のボディを含むスタブを実装してこれを回避し、コールバッククライアントにそのスタブを継承させることができますが、すでに別の基本クラスから継承している場合、これは不可能です。多分あなたはある種の動的プロキシコールバックを使うことができます( http://developer.Android.com/reference/Java/lang/reflect/Proxy.html を参照してください)が、それは本当に複雑になり、私は別のメカニズムを使用することを考えます。
  • コールバック呼び出しのクライアントは、サービスの呼び出し元から直接アクセスできない場合、さまざまなメソッド/コンポーネントを介して伝達する必要があります。

BroadcastReceiver-アプローチに関するいくつかのポイント:

プロ

  • コンポーネント間の疎結合を実現します。
  • 1対nの関係(1対0を含む)を持つことができます。
  • onReceive()メソッドは常にメインスレッドで実行されます。
  • アプリケーション全体のコンポーネントに通知できるので、通信するコンポーネントが互いに「見える」必要はありません。

コントラ

  • これは非常に一般的なアプローチであるため、Intentによって転送されるデータのマーシャリングとアンマーシャリングは追加のエラーソースです。
  • 他のアプリとの相関関係を排除したい場合は、Intentのアクションを一意にする必要があります(パッケージ名の先頭に追加するなど)。その本来の目的は、アプリケーション間のブロードキャストを行うことです。
  • BroadcastReceiver- registrationおよびunregistrationを管理する必要があります。これをより快適な方法で行いたい場合は、登録する必要のあるアクションでアクティビティに注釈を付けるカスタムアノテーションを実装し、onResume()Activitysの登録と登録解除を行うベースIntentFilterclassを実装できます。それぞれ。 onPause() methods。
  • すでに述べたように、Intentで送信されるデータはParcelableインターフェースを実装する必要がありますが、さらに厳密なサイズ制限があり、Intentで大量のデータを転送するとパフォーマンスの問題が発生します。これについての議論は http://code.google.com/p/Android/issues/detail?id=5878 を参照してください。したがって、たとえば画像を送信する場合は、一時的にリポジトリに保存し、対応するIDまたはURLを送信して、使用後にリポジトリから画像を削除するIntentのレシーバーから画像にアクセスする必要があります。複数のレシーバーがある場合、これによりさらに問題が発生します(いつイメージをリポジトリーから削除する必要があり、誰が削除する必要がありますか?)。
  • この種の通知メカニズムを使いすぎると、アプリケーションの制御フローが非表示になり、デバッグ時にIntentsのシーケンスでグラフを描画することになり、特定のエラーの原因となった原因や、この通知チェーンがどこかで壊れた理由がわかります。

私の意見では、モバイルアプリでも、少なくとも2つのレイヤー(UIレイヤーとコアレイヤー(ビジネスロジックなどを含む))に基づくアーキテクチャが必要です。一般に、長時間実行タスクはコアレイヤー内の独自のスレッドで(おそらくAsyncTaskまたはHandlerThreadを使用する場合はMessageQueueを介して)実行され、このタスクが完了したらUIを更新する必要があります。一般に、コールバックを使用すると、コンポーネント間の密結合が実現されるため、このアプローチはレイヤー内でのみ使用し、レイヤーの境界を越えた通信には使用しないことをお勧めします。 UIレイヤーとコアレイヤーの間のメッセージブロードキャストでは、ロジックレイヤーからUIレイヤーを分離できるBroadcastReceiver-アプローチを使用します。

82
Andreas Klöber

あなたの場合、BroadcastReceiverを使って何が得られるかわかりません。コールバック、またはおそらくHandlersがその方法です。 BroadcastReceiverは、サブスクライバーが誰かわからない場合に適しています。

私はあなたがすでに受け取った他の素晴らしい答えに別のオプションを追加します...

インテントを受信するためにブロードキャストレシーバーを作成する必要はありません。 Androidマニフェストファイルに、インテントを受信するためのアクティビティを登録できます。

_<activity Android:name=".MyActivity">
        <intent-filter >
              <action Android:name="intent.you.want.to.receive" /> 
              <category Android:name="Android.intent.category.DEFAULT" /> 
        </intent-filter>     
....
</activity>
_

次に、アクティビティのonNewIntent(Intent)メソッドをオーバーライドして受け取ります。

インテントを送信するには、Context.startActivity(Intent)メソッドを使用します。おそらく、_FLAG_ACTIVITY_SINGLE_TOP_フラグをインテントに追加して、アクティビティのインスタンスが既に実行されている場合に、アクティビティの新しいインスタンスが作成されないようにする必要があります。

編集:私はあなたが単一のアプリケーション内で実行されていることに気づきました。したがって、単純なコールバックがおそらく最善です。上記のソリューションは単一のアプリで機能しますが、さまざまなアプリケーションに適しています。これは誰かを助けるためにここに置いておきます。幸運を!

3
objbuilder

Broadcastreceiversを使用する必要があるのは、アプリケーション間でブロードキャストを送信する必要がある場合です。

これら2つ以外を使用する場合は、 Observer (インターフェースはAndroidに含まれています)とデリゲートの使用を検討してください。

デリゲートについては this SO post を検討してください。

2
silwar

目標は不明ですが、intentとbroadcastReceiverを使用するという同じ考えを維持し、通常のbroadcastReceiversよりも優れたパフォーマンスとセキュリティが必要な場合は、Androidサポートで利用できるこのデモを試すことができます図書館 :

http://developer.Android.com/resources/samples/Support4Demos/src/com/example/Android/supportv4/content/LocalServiceBroadcaster.html

そうでない場合は、常にasyncTask、service、handlersなどを使用できます。

1