57

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

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

わかりました、私が言うことをあなたが理解したことを願っています:)。

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

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

4

5 に答える 5

86

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

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

プロ

  • 実装は簡単で簡単です。
  • 相互作用するコンポーネント間で型安全性が得られます。
  • 任意のオブジェクトを返すことができます。
  • 単体テストでモックコールバック(たとえば、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を管理する必要があります。これをより快適な方法で実行したい場合は、カスタムアノテーションを実装して、登録する必要のあるアクションでアクティビティにアノテーションを付け、それぞれにsをActivity使用して登録と登録解除を行う基本クラスを実装できます。メソッド。IntentFilteronResume()onPause()
  • すでに述べたように、で送信されるデータはインターフェイスIntentを実装するParcelable必要がありますが、さらに厳密なサイズ制限があり、で大量のデータを転送するとパフォーマンスの問題が発生しますIntent。これに関する議論については、http://code.google.com/p/android/issues/detail?id=5878を参照してください。したがって、たとえば画像を送信する場合は、画像を一時的にリポジトリに保存し、対応するIDまたはURLを送信して、Intent使用後にリポジトリから画像を削除する受信者から画像にアクセスする必要があります。複数のレシーバーがある場合、これはさらに問題につながります(いつイメージをリポジトリーから削除する必要があり、誰がそれを行う必要がありますか?)。
  • この種の通知メカニズムを使いすぎると、アプリケーションの制御フローが隠れてしまう可能性があり、デバッグ時にIntent、特定のエラーを引き起こした原因や、ある時点でこの通知チェーンが壊れた理由を理解するために、一連のsを含むグラフを描画することになります。

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

于 2012-05-20T10:31:13.623 に答える
6

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

于 2012-05-13T21:27:19.863 に答える
3

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

インテントを受信するためにブロードキャストレシーバーを作成する必要はありません。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フラグをインテントに追加して、アクティビティの新しいインスタンスがすでに実行されている場合にそれが作成されないようにする必要があります。

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

于 2012-05-16T16:15:46.397 に答える
2

コールバック(またはAlexが提案するハンドラー)が状況に適しているときに、アプリケーション間でブロードキャストを送信する必要がある場合は、ブロードキャストレシーバーを使用する必要があります。

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

代理人については、このSO投稿を検討してください。

于 2012-05-16T12:55:15.423 に答える
1

目標が何であるかはわかりませんが、intentとbroadcastReceiverを使用するという同じ考えを維持し、通常のbroadcastReceiversよりも優れたパフォーマンスとセキュリティが必要な場合は、Androidサポートライブラリで利用できるこのデモを試すことができます。

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

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

于 2012-05-16T20:30:11.167 に答える