Check on the Internet where to place when using MVP, RX and retrofit

I went through this and this post. Therefore, I really agree with the second message that the presenter should not know about the specifics of Android. So I think this is an online service level check. I use Java Rx to create network calls, so I can either put a network check before the service call, so I need to manually throw an IOException too, because I need to show the error page when the network is unavailable, another option - I create my own class errors without the 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(); } }); 

Another way I want to add an interceptor in OkHttpClient and set it to update

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

Now the second approach is more scalable, but I'm not sure that it will be effective, since I will unnecessarily refer to the service method and the call.execute () method.

Any suggestion how to use it? Also my parameter for evaluating the path

  • Efficiency

  • Scalability

  • General: I want the same logic to be used in applications that follow a similar architecture, where MVP and / DataProvider repository (can provide data from the / db network)

Other suggestions are also welcome if you are already using any other method.

+7
android architecture mvp rx-java retrofit2
source share
1 answer

First, we create a utility for checking the Internet connection, there are two ways to create this utility: the one where the utility gives the status only once, which looks like this:

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

Another way to create this utility is that the utility continues to emit connection status if it changes, which looks like this:

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

Then, in your data source or Presenter, use switchMap or flatMap to check your Internet connection before you perform any network operation that looks like this:

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

Note that we use switchMap instead of flatMap. why switchMap? because we have 2 data streams here, first it's an internet connection, and the second is “Retrofit”. first we will get the connection status value (true / false), if we have an active connection, we will create a new Retrofit stream and begin to receive the results, in line, if we change the connection status, switchMap will first stop the existing one Re-connect, and then decide if you need whether we start a new one or ignore it.

EDIT: This is one example that can give better clarity https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/ dataSource / GitHubUserListDataSource.java

EDIT2:

So, you mean that the switch card will try on its own when the Internet returns?

Yes and No, first look at the difference between flatMap and switchMap. Let's say we have editText, and we look at some information from the network based on what types of users, each time a user adds a new character, we have to make a new request (which can be reduced using debounce), now with so many network calls only the latest results are useful, with flatMap we get all the results from all the calls we made on the network, with switchMap , on the other hand, the moment we make a request, all previous calls are discarded.

Now the solution here consists of 2 parts,

  • We need an Observation that keeps emitting the current status of the Network, the first InternetConnection above sends the status once and calls onComplete (), but the second has a broadcast receiver, and it will continue to send onNext () when the network status changes. IF you need to make a reactive decision for case-2

  • Let's say you choose case-2 for InternetConnection, in this case use switchMap (), cause the network status to change, we need to stop the “Retrofit” from what it is doing, and then, based on the network status, make a new call or not call .

How can I find out that the error is the Internet, and it will be scalable, because I need to make any suggestions regarding writing a wrapper with every network call?

Writing a wrapper would be a great choice, you can create your own answer that can take multiple entries from a set of possible answers, for example. SUCCESS_INTERNET, SUCCESS_LOGIN, ERROR_INVALID_ID

EDIT3: find the updated InternetConnectionUtil here https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/util/InternetConnection.java

More details on the same topic can be found here: https://medium.com/@Viraj.Tank/android-mvp-that-survives-view-life-cycle-configuration-internet-changes-part-2-6b1e2b5c5294

EDIT4: Recently I created an Internet utility using the Android Architecture components - LiveData, here you can find the full source code, https://github.com/viraj49/Internet-Utitliy-using-AAC-LiveData

Detailed code description here, https://medium.com/@Viraj.Tank/internet-utility-using-android-architecture-components-livedata-e828a0fcd3db

+9
source share

All Articles