web-dev-qa-db-ja.com

BroadcastReceiverをAndroid MVP?

ネットワーク接続イベントを受信するBroadcastReceiver実装があります。 AndroidManifest.xmlで宣言され、ネットワークイベントが発生すると自動的にAndroidによって呼び出されます。

BroadcastReceiver:

public class ConnectivityChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.v(TAG, "action: " + intent.getAction());
        Log.v(TAG, "component: " + intent.getComponent());
    }
}

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="com.example.test">

    <uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE" />

    <application
        Android:allowBackup="true"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/app_name"
        Android:supportsRtl="true"
        Android:theme="@style/AppTheme">
        ...
        <receiver
            Android:name=".ConnectivityChangeReceiver"
            Android:enabled="true">
            <intent-filter>
                <action Android:name="Android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

ここで説明するGoogleのMVPサンプルアーキテクチャをアプリに使用したいと思います。

https://github.com/googlesamples/Android-architecture/tree/todo-mvp/

上記のアーキテクチャを使用して、疑問に思うだけです。

  1. BroadcastReceiverはどこに配置する必要がありますか?

  2. BroadcastReceiverがデータベースに書き込む必要がある場合、これを行うための最良の方法は何ですか?

  3. BroadcastReceiverがUIを更新する必要がある場合、これを行うための最良の方法は何ですか?

18
Rory
  1. 個人的には、BroadcastReceiverからのイベントをプレゼンターに配信する必要があると思います。
  2. ステートメント1に基づいて、プレゼンターは、db操作を処理する必要があるInteractor/Contract/Use caseへの参照を保持します。

    BroadcastReceiver --event-> Presenter-> Interactor ---> Repository

  3. ステートメント1に基づいて、プレゼンターはイベントを消費し、ビューを呼び出す必要があります。

    BroadcastReceiver --event-> Presenter-> (多分何かをする、ビジネスロジック) ---> View

これが私が持っているもので、私が言ったことを要約した最小限のサンプルスニペットです:

  private class NetworkBroadcastReceiver23 extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //... redacted code.../
            boolean connected = activeNetworkInfo != null && activeNetworkInfo.isConnected();
            mPresenter.onConnectionChanged(activeNetworkInfo,connected);
        }
    }

そこからイベントをプレゼンターにストリーミングするため、レシーバーをアクティビティに配置します。これにより、プレゼンターの接続変更のテストが容易になります。プラットフォームイベントの関心の分離を達成するのは難しいので、レイヤーをAndroid sdkコンポーネントとクラスから解放したかったのです。AlexShutovが指摘した別の方法は、MVPとObserverパターンを混合することです。 BroadcastReceiverをイベントソースではなく外部エンティティと見なす場合。

はい、NetworkInfoパラメータを削除することでメソッドを改善できることに同意します。

11

MVPデザインパターンでは、モデルには外界と接続するためのすべてのエンティティがあります(たとえば、データをフェッチしてローカルに保持するためのリポジトリ)。ブロードキャストレシーバーは外部イベントの入力であり、最終的にはモデルを変更します。良い比較は、六角形のアーキテクチャの「入力ポート」です。

プレゼンターはモデルからのデータを表示する方法を定義しますが、別のシステムやユーザーイベントへの反応を含むすべてのビジネスロジックはモデル内にあると想定されています。

ビューとプレゼンターは、実行中のモードプログラムに応じて動的に変更できます。たとえば、別のバージョンのUIを使用したい場合や、より単純なUIの動作を使用したい場合ですが、外部イベントへの反応を含め、すべてのロジックは同じままである必要があります。そのため、BroadcastReceiverをモデル内に配置する必要があります。

少なくともMVPパターンに従っている場合、Activityは(View)のシステムコンテナであるため、BroadcastレシーバーをActivityに配置しないでください。プロジェクトが非常に複雑な場合は、テスト中に簡単にモックしてモデル内で使用できる「ExternalInput」インターフェイスを使用してBroadcastReceiverから抽象化することを検討してください。

3
Alex Shutov

機能ごとにパッケージ化する場合は、機能パッケージ内にreceiverパッケージを作成し、その中にBroadcastReceiverクラスを配置するだけです。サブパッケージがない場合は、機能パッケージにBroadcastReceiverクラスを入れるだけです。

0
pavle