Comprobación de Internet, dónde colocar al usar MVP, RX y Retrofit

He pasado por esto y este post. Así que estoy realmente de acuerdo con el segundo post que el presentador no debe ser consciente de la cosa específica de Android. Así que lo que estoy pensando es poner la comprobación de Internet en la capa de servicio. Estoy utilizando Rx Java para hacer llamadas de red, así que puede colocar la comprobación de red antes de hacer una llamada de servicio, por lo que de esta manera tengo que lanzar manualmente y IOException porque tengo que mostrar una página de error en la vista cuando la red no está disponible, La otra opción es crear mi propia clase de error para no Internet

Observable<PaginationResponse<Notification>> response = Observable.create(new Observable.OnSubscribe<PaginationResponse<Notification>>() { @Override public void call(Subscriber<? super PaginationResponse<Notification>> subscriber) { if (isNetworkConnected()) { Call<List<Notification>> call = mService.getNotifications(); try { Response<List<Notification>> response = call.execute(); processPaginationResponse(subscriber, response); } catch (IOException e) { e.printStackTrace(); subscriber.onError(e); } } else { //This is I am adding manually subscriber.onError(new IOException); } subscriber.onCompleted(); } }); 

La otra manera que yo pienso de está agregando el interceptor a OkHttpClient y lo fijo para retrofit

 OkHttpClient.Builder builder = new OkHttpClient().newBuilder(); builder.addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { if (!isNetworkConnected()) { throw new IOException(); } final Request.Builder builder = chain.request().newBuilder(); Request request = builder.build(); return chain.proceed(request); } }); 

Ahora el segundo enfoque es más escalable, pero no estoy seguro de que será eficiente, ya que sería innecesariamente llamar al método de servicio y el método call.execute ().

Cualquier sugerencia de qué manera debe ser utilizado? También mi parámetro para juzgar el camino es

  • Eficiencia

  • Escalabilidad

  • Genérico: Quiero que esta misma lógica se pueda usar entre las aplicaciones que están siguiendo la arquitectura similar donde MVP y Repository / DataProvider (pueden dar datos de la red / db)

Otras sugerencias también son bienvenidas, si la gente ya está usando cualquier otra forma.

En primer lugar creamos una utilidad para comprobar la conexión a Internet, hay dos maneras en que podemos crear esta utilidad, una donde la utilidad emite el estado sólo una vez, que se parece a esto,

 public class InternetConnection { public static Observable<Boolean> isInternetOn(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return Observable.just(activeNetworkInfo != null && activeNetworkInfo.isConnected()); } } 

Otra forma de crear esta utilidad es, donde la utilidad sigue emitiendo el estado de la conexión si cambia, que se parece a esto,

 public class InternetConnection { public Observable<Boolean> isInternetOn(Context context) { final IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); return Observable.create(new Observable.OnSubscribe<Boolean>() { @Override public void call(final Subscriber<? super Boolean> subscriber) { final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); subscriber.onNext(netInfo != null && netInfo.isConnected()); } }; context.registerReceiver(receiver, filter); subscriber.add(unsubscribeInUiThread(() -> context.unregisterReceiver(receiver))); } }).defaultIfEmpty(false); } private Subscription unsubscribeInUiThread(final Action0 unsubscribe) { return Subscriptions.create(() -> { if (Looper.getMainLooper() == Looper.myLooper()) { unsubscribe.call(); } else { final Scheduler.Worker inner = AndroidSchedulers.mainThread().createWorker(); inner.schedule(() -> { unsubscribe.call(); inner.unsubscribe(); }); } }); } } 

A continuación, en su dataSource o Presenter use switchMap o flatMap para comprobar la conexión a Internet antes de realizar cualquier operación de red que tenga este aspecto,

 private Observable<List<GitHubUser>> getGitHubUsersFromRetrofit() { return isInternetOn(context) .filter(connectionStatus -> connectionStatus) .switchMap(connectionStatus -> gitHubApiInterface.getGitHubUsersList() .map(gitHubUserList -> { gitHubUserDao.storeOrUpdateGitHubUserList(gitHubUserList); return gitHubUserList; })); } 

Tenga en cuenta que, estamos utilizando switchMap en lugar de flatMap. ¿Por qué switchMap? Porque, tenemos 2 flujo de datos aquí, primero es la conexión a Internet y el segundo es Retrofit. Primero vamos a tomar el valor de estado de conexión (verdadero / falso), si tenemos conexión activa, vamos a crear un nuevo flujo de Retrofit y volver a empezar a obtener resultados, por la línea si el estado de la conexión cambia, switchMap primero detener el actual Reajuste la conexión y luego decida si necesitamos iniciar una nueva o ignorarla.

EDIT: Este es uno de los ejemplos, lo que podría dar una mayor claridad https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/ Realm / dataSource / GitHubUserListDataSource.java

EDIT2:

¿Quiere decir que el mapa de conmutación lo intentará una vez que Internet esté de vuelta?

Sí y No, veamos primero la diferencia entre flatMap y switchMap. Digamos que tenemos un editText y buscamos alguna información de la red basada en qué tipo de usuario, cada vez que el usuario añade un nuevo carácter tenemos que hacer una nueva consulta (que se puede reducir con debounce), ahora con tantas llamadas de red sólo el Los últimos resultados son útiles, con flatMap vamos a recibir todos los resultados de todas las llamadas que hicimos a la red, con switchMap por otro lado, el momento de hacer una consulta, todas las llamadas anteriores se descartan.

Ahora la solución aquí está hecha de 2 partes,

  1. Necesitamos un observable que siga emitiendo el estado actual de la red, el primer InternetConnection arriba envía el estado una vez y las llamadas onComplete (), pero el segundo tiene un receptor de la difusión y continuará enviando onNext () cuando cambia el estado de la red. SI usted necesita para hacer una solución reactiva ir para el caso-2

  2. Supongamos que eliges el caso de InternetConnection-2, en este caso usamos switchMap (), causamos cuando cambia el estado de la red, necesitamos detener Retrofit de lo que esté haciendo y basándonos en el estado de la red, o hacer una nueva llamada o no Haz una llamada.

¿Cómo puedo dejar que mi vista sabe que el error es Internet uno también será esto escalable porque tengo que hacer con cada llamada de red, cualquier sugerencia sobre la escritura de un envoltorio?

Escribir un envoltorio sería excelente elección, puede crear su propia respuesta personalizada que puede tomar varias entradas de un conjunto de posibles respuestas, por ejemplo, SUCCESS_INTERNET, SUCCESS_LOGIN, ERROR_INVALID_ID

EDIT3: Por favor, encuentre un InternetConnectionUtil actualizado aquí https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/util/InternetConnection. Java

Más detalles sobre el mismo tema están aquí: https://medium.com/@Viraj.Tank/android-mvp-that-survives-view-life-cycle-configuration-internet-changes-part-2-6b1e2b5c5294

EDIT4: Recientemente he creado una utilidad de Internet utilizando componentes de arquitectura de Android – LiveData, puede encontrar código fuente completo aquí, https://github.com/viraj49/Internet-Utitliy-using-AAC-LiveData

Una descripción detallada del código está aquí, https://medium.com/@Viraj.Tank/internet-utility-using-android-architecture-components-livedata-e828a0fcd3db

  • ¿Cómo terminar un observable?
  • RxJava patrón para solicitar un remoto Observable con una caché temporal
  • Evento de RxJava de incendio sólo cambia cuando Fragmento es visible en ViewPager
  • Encadenar dos observables de adaptación con RxJava
  • Uso de RoboSpice y RxJava
  • Retrofit no desencadena onError cuando se utiliza ErrorHandler personalizado
  • RxJava No puede crear el controlador dentro de hilo que no ha llamado Looper.prepare ()
  • Cómo crear un objeto retrofit.Response durante las pruebas de unidad con Retrofit 2
  • RxJava solicitudes de red y almacenamiento en caché
  • Proguard y RxAndroid V1.1.0
  • ¿Es posible obtener 2 valores en onNext () de suscriptor en rxjava android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.