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