web-dev-qa-db-fra.com

Où placer BroadcastReceiver dans Android MVP?

J'ai une implémentation BroadcastReceiver qui reçoit des événements de connexion réseau. Il est déclaré dans le fichier AndroidManifest.xml et est appelé automatiquement par Android lorsque des événements réseau se produisent.

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>

J'aimerais utiliser l'exemple d'architecture MVP de Google décrit ici pour mon application:

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

En utilisant l'architecture ci-dessus, je me demandais:

  1. Où faut-il placer mon BroadcastReceiver?

  2. Si mon BroadcastReceiver doit écrire dans la base de données, quel est le meilleur moyen de le faire?

  3. Si mon BroadcastReceiver doit mettre à jour l'interface utilisateur, quel est le meilleur moyen de le faire?

16
Rory
  1. Personnellement, j’estime que les événements de la BroadcastReceiverdevraient être transmis au présentateur.
  2. Sur la base de l'instruction 1, le présentateur contient une référence au Interactorname __/Contractname __/Use case qui devrait gérer les opérations de base de données.

    BroadcastReceiver- event -> Presenter-> Interactor---> Repositoryname__

  3. Sur la base de la déclaration 1, le présentateur doit à nouveau utiliser l'événement et appeler la vue. 

    BroadcastReceiver- event -> Presenter-> (peut-être quelques trucs, logique métier) ---> Viewname__

Voici ce que j'ai, un extrait d'exemple minimal qui résume ce que j'ai dit:

  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);
        }
    }

Placez le récepteur dans l'activité, car à partir de là, vous transmettez des événements au présentateur. Cela facilitera le test du présentateur pour le changement de connexion. Il est difficile de séparer les préoccupations des événements de plate-forme. Je voulais que mes couches restent exemptes de composants et de classes Android SDK. Alex Shutov a souligné qu'une autre solution consiste à mélanger les modèles MVP et Observer si vous envisagez de prendre BroadcastReceiver en tant qu'entité externe plutôt qu'en tant que source d'événements. 

Oui, je conviens que vous pouvez améliorer la méthode en supprimant le paramètre NetworkInfoname__.

8
Nikola Despotoski

Dans le modèle de conception MVP, Model possède toutes les entités pour la connexion au monde extérieur (par exemple, Référentiel pour extraire des données et les conserver localement). Le récepteur de diffusion est une entrée pour les événements externes, qui, éventuellement, modifieront le modèle. Une bonne comparaison est un «port d'entrée» dans une architecture hexagonale. 

Presenter définit le mode d'affichage des données à partir d'un modèle, mais toute logique logique, y compris la réaction à un autre système ou à des événements utilisateur, est censée se trouver à l'intérieur du modèle. 

View and Presenter peut être modifié de manière dynamique en fonction du programme en mode exécuté, par exemple, si vous souhaitez utiliser une autre version de l'interface utilisateur ou un comportement plus simpliste de l'interface utilisateur, mais toute la logique doit rester la même, y compris la réaction aux événements externes. C'est pourquoi BroadcastReceiver doit être placé à l'intérieur du modèle.

Vous ne devez JAMAIS placer Broadcast receiver dans Activity, car Activity est un conteneur système pour (View), du moins si vous suivez le modèle MVP. Si votre projet est assez complexe, envisagez d’abréger BroadcastReceiver à l’aide d’une interface «ExternalInput», qui peut être facilement simulée pendant les tests et utilisée dans Model.

3
Alex Shutov

Si vous empaquetez par fonction, vous pouvez simplement créer un paquet receiver dans un paquet de fonctions et y placer la classe BroadcastReceiver. Si vous n'avez pas de sous-paquetages, mettez simplement la classe BroadcastReceiver dans votre paquet de fonctionnalités.

0
pavle