我正在使用Rx Java进行网络调用,所以我可以在进行服务调用之前进行网络检查,这样我就需要手动抛出和IOException,因为我需要在网络不可用时在视图上显示错误页面,另一个选择是我为没有互联网创建我自己的错误类
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(); } });
我的另一种方法是将拦截器添加到OkHttpClient并将其设置为改装
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); } });
现在第二种方法更具可扩展性,但我不确定它是否有效,因为我将不必要地调用service方法和call.execute()方法.
有什么建议应该使用哪种方式?
我的判断方式也是我的参数
>效率
>可扩展性
> Generic:我希望这个相同的逻辑可用于遵循类似架构的应用程序,其中MVP和Repository / DataProvider(可以从network / db提供数据)
如果您的人已经在使用任何其他方式,也欢迎其他建议.
解决方法
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()); } }
创建此实用程序的其他方法是,如果实用程序发生更改,它将继续发出连接状态,如下所示:
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(); }); } }); } }
接下来,在您的dataSource或Presenter中使用switchMap或flatMap检查互联网连接,然后再进行任何网络操作,如下所示:
private Observable<List<GitHubUser>> getGitHubUsersFromRetrofit() { return isInternetOn(context) .filter(connectionStatus -> connectionStatus) .switchMap(connectionStatus -> gitHubApiInterface.getGitHubUsersList() .map(gitHubUserList -> { gitHubUserDao.storeOrUpdateGitHubUserList(gitHubUserList); return gitHubUserList; })); }
请注意,我们使用的是switchMap而不是flatMap.为什么switchMap?因为,我们这里有2个数据流,第一个是互联网连接,第二个是Retrofit.首先我们将获取连接状态值(true / false),如果我们有活动连接,我们将创建一个新的Retrofit流并返回开始获取结果,如果我们连接状态发生变化,switchMap将首先停止现有改进连接,然后决定是否需要启动新的或忽略它.
编辑:
这是样本之一,可能会提供更好的清晰度https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/dataSource/GitHubUserListDataSource.java
EDIT2:
所以你的意思是一旦互联网回来,开关地图会自己尝试吗?
是和否,我们首先看看flatMap和amp;之间的区别. switchMap.假设我们有一个editText,我们根据用户类型从网络中搜索一些信息,每次用户添加一个新的字符时我们都要进行新的查询(可以通过去抖动减少),现在只有这么多的网络调用最新的结果是有用的,使用flatMap,我们将收到我们对网络进行的所有调用的所有结果,另一方面,使用switchMap,当我们进行查询时,所有先前的调用都将被丢弃.
现在解决方案由2部分组成,
>我们需要一个持续发出网络当前状态的Observable,上面的第一个InternetConnection发送状态一次并调用onComplete(),但第二个有一个Broadcast接收器,它将在网络状态改变时继续发送onNext().如果你需要制定一个反应性解决方案,请选择案例2
>假设你选择了InternetConnection case-2,在这种情况下使用switchMap(),因为当网络状态发生变化时,我们需要停止Retrofit的工作,然后根据网络状态进行新的调用或者不要打个电话.
如何让我的视图知道错误是互联网,这也是可扩展的,因为我需要处理每个网络调用,有关编写包装器的任何建议吗?
编写包装器是一个很好的选择,您可以创建自己的自定义响应,该响应可以从一组可能的响应中获取多个条目,例如: SUCCESS_INTERNET,SUCCESS_LOGIN,ERROR_INVALID_ID
EDIT3:请在此处找到更新的InternetConnectionUtil https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/util/InternetConnection.java
关于同一主题的更多细节在这里:https://medium.com/@Viraj.Tank/android-mvp-that-survives-view-life-cycle-configuration-internet-changes-part-2-6b1e2b5c5294
EDIT4:我最近使用Android架构组件创建了一个Internet实用程序 – LiveData,你可以在这里找到完整的源代码,
https://github.com/viraj49/Internet-Utitliy-using-AAC-LiveData
这里有代码的详细描述,
https://medium.com/@Viraj.Tank/internet-utility-using-android-architecture-components-livedata-e828a0fcd3db