¿Dónde poner BroadcastReceiver en Android MVP?
(5)
Tengo una implementación de BroadcastReceiver que recibe eventos de conexión de red. se declara en el AndroidManifest.xml y es llamado por Android automáticamente cuando ocurren eventos de red.
Receptor de radiodifusión:
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>
Me gustaría usar la arquitectura de muestra MVP de Google que se describe aquí para mi aplicación:
https://github.com/googlesamples/android-architecture/tree/todo-mvp/
Usando la arquitectura anterior, solo me pregunto:
¿Dónde debería colocarse mi BroadcastReceiver?
Si mi BroadcastReceiver necesita escribir en la base de datos, ¿cuál es la mejor manera de hacerlo?
Si mi BroadcastReceiver necesita actualizar la interfaz de usuario, ¿cuál es la mejor manera de hacerlo?
- Personalmente, creo que los eventos de
BroadcastReceiver
deben entregarse al presentador. Basado en la declaración 1, el presentador mantiene una referencia al
Interactor
/Contract
/Use case
que debe manejar las operaciones de db.BroadcastReceiver
- evento ->Presenter
->Interactor
--->Repository
Basado en la declaración 1, nuevamente el presentador debe consumir el evento y hacer una llamada a la Vista.
BroadcastReceiver
- evento ->Presenter
-> (tal vez hacer algunas cosas, lógica de negocios) --->View
Aquí está lo que tengo, un fragmento de ejemplo mínimo que resume lo que dije:
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);
}
}
Coloque el receptor en la actividad, porque desde allí transmite los eventos al presentador. Esto facilitará las pruebas del presentador para el cambio de conexión. Es difícil lograr la separación de la preocupación por los eventos de la plataforma, quería mantener mis capas libres de componentes y clases de Android SDK. Otra manera, señalada por Alex Shutov, es mezclar el patrón de MVP y Observer si consideras BroadcastReceiver como una entidad externa, en lugar de una fuente de eventos.
Sí, estoy de acuerdo en que puede mejorar el método NetworkInfo
el NetworkInfo
.
En el patrón de diseño de MVP, el modelo tiene todas las entidades para la conexión con el mundo exterior (por ejemplo, Repositorio para obtener datos y conservarlos localmente). El receptor de difusión es una entrada para eventos externos que, eventualmente, modificará el modelo. Una buena comparación es un ''puerto de entrada'' en la arquitectura hexagonal.
Presenter define la forma de mostrar los datos del modelo, pero se supone que toda la lógica empresarial, incluida la reacción a otro sistema o eventos de usuario, está dentro del modelo.
View y Presenter se pueden cambiar dinámicamente según el programa de modo que se ejecute, por ejemplo, si desea usar otra versión de UI o un comportamiento de UI más simplista, pero toda la lógica debe permanecer igual, incluida la reacción ante eventos externos. Es por eso que BroadcastReceiver debe colocarse dentro del modelo.
NUNCA debe colocar el receptor de difusión en Actividad, ya que Actividad es un contenedor del sistema para (Ver), al menos si sigue el patrón MVP. En caso de que su proyecto sea bastante complejo, considere la posibilidad de abstraerse de BroadcastReceiver mediante alguna interfaz ''ExternalInput'', que se puede burlar fácilmente durante la prueba y usarla dentro del Modelo.
Si está empaquetando por característica, puede simplemente crear un paquete receiver
dentro del paquete de características y colocar la clase BroadcastReceiver
en él. Si no tiene subpaquetes, simplemente coloque la clase BroadcastReceiver
en su paquete de características.
Si necesita realizar operaciones en la base de datos / Actualizar la interfaz de usuario, debe colocar BroadcastReceiver en la actividad correspondiente.
Aquí está el código de ejemplo.
public class YourActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
// public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mConnectivityReceiver);
}
public BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
checkIntent(intent);
}
private void checkIntent(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
NetworkInfo networkInfo = (NetworkInfo) bundle.get("networkInfo");
doYourStuff(networkInfo.isConnected());
}
}
};
private void doYourStuff(boolean isNetworkConnected) {
//Update your UI here
//Do database Operations here
}
}
Haz tus cosas en doYourStuff () basado en conectividad de red.
A través de este enfoque, no necesita registrar su BroadcastReceiver en el archivo Menifest.xml.
Su emisión debe ser Ver . Luego, llama al método Presenter , que cambia el estado de algunos NetworkStateService
(que es el nivel de modelo ). Cuando cambia el estado de NetworkStateService
, notifica a los Presentadores , que la red está disponible y pueden realizar solicitudes. Y estos presentadores deben actualizar la interfaz de usuario. Todos estos presentadores deben ser como oyentes en NetworkStateService.
Para operaciones largas, como trabajar con db o red, debe iniciar el Service
. La razón de esto es que la transmisión se cancelará después de 10 segundos desde la recepción. Debe incluir a Presenter en este Service
y trabajar con Model from this Presenter .