web-dev-qa-db-ja.com

Kotlinコルーチンを使用してFirebaseメッセージングのLocalBroadcastManagerを置き換える

Androidで Firebase Cloud Messaging を使用する場合、多くの場合、現在のActivityに着信プッシュ通知を通知することが望まれます。これを行うための推奨される方法の1つは、 LocalBroadcastManager を使用してIntentFirebaseMessagingService実装からActivityに送信することです( StackOverflowの例の回答 )。

ただし、バージョン1.1.0-alpha01(2018-12-17)以降、 LocalBroadcastManagerは非推奨

LocalBroadcastManagerはアプリケーション全体のイベントバスであり、アプリのレイヤー違反を受け入れます。どのコンポーネントも他のコンポーネントからのイベントをリッスンする可能性があります。ユースケースに応じて、LocalBroadcastManagerの使用を観察可能なパターンの他の実装に置き換えることができます。適切なオプションは LiveData またはリアクティブストリームです。

このクラスはしばらくの間利用できる可能性が高いですが、とにかくアプリケーションのクリーンアップを開始したいので、Googleが古い方法を実際に削除する前に、より良いものに移行したいと思います。

現在、これらのローカルブロードキャストには、アプリで2つの主要な役割があります。

  1. プッシュ通知からの新しいデータでUIを更新します。これが機能する方法は、受信したプッシュデータを処理する各Activityが、適切なメッセージをリッスンし、独自のビューデータを更新するブロードキャストレシーバーを持っていることです。
  2. サーバーがセッションを終了する通知を送信する場合、ユーザーにログアウトを強制します。これは、ログアウトイベントをリッスンし、アクティビティを終了し、ログインアクティビティを開始するブロードキャストレシーバーのインスタンスを持つ各アクティビティで機能します。

私が見ているように、これらのユースケースには、提案されている代替案の両方に問題があります。

  • LiveDataは、ActivityまたはFragmentViewModelの一部として使用するのが最も簡単です。ただし、ViewModelは、UIを直接処理するクラスからの使用のみを目的としています。 ViewModel内からFirebaseMessagingServiceにアクセスすることは醜いハックが必要であり、アーキテクチャーの観点からは非常に悪い考えです。また、異なるアクティビティとフラグメントには異なるViewModelオブジェクトがあり、サービスがそれらすべてにアクセスする必要はありません。
  • 一連のobjectプロパティを使用してKotlin LiveData(別名シングルトン)を作成し、FirebaseMessagingServiceで受信メッセージからこれらのLiveDataオブジェクトを更新し、Activityでこれらの変更を監視して独自のViewModelLiveDataプロパティにコピーすることができます。これに関する問題は2つあります。最初に、データの各部分に対して2つの同一のLiveDataオブジェクトが必要です。1つはViewModelにあり、もう1つはobjectにあります。 2番目に、LiveDataはイベントのストリームをリッスンするのではなく、データの変更を処理することを目的としているため、「ログアウトイベント」の処理には役立ちません。 (これで LiveData Event Wrapper を使用して2番目の問題を処理できるかもしれませんが、それでも、この方法で動作することを意図していない何かに対する悪いハックのように感じます。)
  • RxJavaなどのリアクティブストリームはおそらく私が必要とするものを実行しますが、私はすでにチームにKotlin、Android Databinding、Android ViewModel、およびa過去数か月の間に他の多くの新機能が追加されましたが、それ以上は対応できないと思います。RxJavaも、この1つの用途だけで追加するのは大きなものであり、アプリケーション全体を書き換えて活用する予定はありません。その追加を正当化するためにそれの。

私が見つけた1つの提案は、ChannelsまたはFlowsでKotlinコルーチンを使用することでした。これらは、リアクティブストリームと非常によく似た方法で使用できますが、(RxJavaとは異なり)Kotlinで使用することを意図しており、Javaに対するKotlinの改善の恩恵を受けています。 GoogleがAndroid開発のためにKotlinに焦点を当てていると発表したため、このオプションは特に魅力的です。

これが最良の選択肢のように思えますが、それが機能するかどうか、およびそのような実装に副作用や落とし穴があるかどうかについて他の人からのフィードバックを見つけることができませんでした。私が見つけた唯一のものは、このようなアプリケーションの例を提供する必要性について、kotlinx.coroutinesリポジトリの 未解決の問題 でした。私はそのような例を提供したいのですが、良い例を作成するのに十分な知識がないと思います。本番用アプリをモルモットにしたくありません。また、この場合、Channelで明示的なコルーチンを使用するのが良いのか、suspendFlowを使用するのが良いのか(または適切であるのか)もわかりません。

要約すれば:

  • Kotlinコルーチンとそれに関連する同時実行構造は、Android ServiceActivityの間の通信を処理する良い方法ですか?
  • はいの場合、ChannelまたはFlow
10
Moshe Katz

コルーチンは、あるソフトウェアコンポーネントから別のソフトウェアコンポーネントへのデータの受け渡しにはあまり役立ちません。これらは、同期のように見える構文を使用して、非同期作業の複数のユニットを処理するのに役立ちます。それがコルーチンの一番下の行です。これらは、JavaScriptの非同期/待機構文に類似しています。コルーチンを使用して非同期ソースのデータにアクセスすることもできますが、そのデータを他のコンポーネントにプロキシする権限はありません。

LiveDataは、おそらくあなたがやろうとしていることに対してうまく機能します。 ViewModelとLiveDataを混同しないでください。さまざまな問題が解決されます。 ViewModelはUIを処理するコードによってのみアクセスされる必要があることは正しいが、そのガイドラインはLiveDataに拡張されない。後でViewModelによって取得され、変換されてビューに渡されるFirebaseMessagingServiceからの現在のデータを反映するLiveDataを公開することは完全に合理的です。このLiveDataはシングルトンにすることも、選択した依存関係注入インフラストラクチャを介して取得することもできます。

LiveDataは実際には状態の変化を管理するためだけに使用されることになっていることに注意してください。これは、アプリがリッスンできるデータの「ストリーム」ではありません。これがうまく機能するためには、インフラストラクチャが状態ベースであることを確認する必要があります。 FCM自体は状態ベースではありませんが、ビューがFCMからのメッセージに応答するようにする場合は、UIが新しいメッセージに一貫して応答するように(またはメッセージがまったくない場合)、各メッセージ間で十分なコンテキストを保持する必要があります。 。

2
Doug Stevenson