互联网检查,使用MVP、RX和Retrofit时该放在哪里 [英] Internet check, where to place when using MVP, RX and Retrofit

查看:19
本文介绍了互联网检查,使用MVP、RX和Retrofit时该放在哪里的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经浏览了这个this 帖子.所以我真的同意第二个帖子,即演示者不应该知道 android 特定的事情.所以我在想的是将互联网检查放在服务层.我正在使用 Rx Java 进行网络调用,所以我可以在进行服务调用之前进行网络检查,所以这样我需要手动抛出和 IOException 因为我需要在网络不可用时在视图中显示错误页面,另一种选择是我为没有互联网创建自己的错误类

I have went through this and this post. So I really agree with the second post that presenter should not be aware of android specific thing. So what I am thinking is putting internet check in service layer. I am using Rx Java for making network calls, so I can either place the network check before making a service call, so this way I need to manually throw and IOException because I need to show an error page on view when network is not available, the other option is I create my own error class for 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();
            }
        });

我想到的另一种方法是将拦截器添加到 OkHttpClient 并将其设置为改造

The other way I though of is adding interceptor to OkHttpClient and set it to 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);
            }
        });

现在第二种方法更具可扩展性,但我不确定它是否有效,因为我会不必要地调用 service 方法和 call.execute() 方法.

Now the 2nd approach is more scalable, but I am not sure it will be efficient as I would be unnecessarily calling service method and call.execute() method.

有什么建议应该使用哪种方式?另外我的判断方式的参数是

Any suggestion which way should be used? Also my parameter for judging the way is

  • 效率

可扩展性

通用:我希望可以在遵循类似架构的应用程序之间使用相同的逻辑,其中 MVP 和 Repository/DataProvider(可能提供来自网络/db 的数据)

Generic : I want this same logic can be used across apps who are following the similar architecture where MVP and Repository/DataProvider (May give data from network/db)

如果您已经在使用任何其他方式,也欢迎提供其他建议.

推荐答案

首先我们创建一个用于检查互联网连接的实用程序,有两种方法可以创建这个实用程序,一种是该实用程序只发出一次状态,看起来像这个,

First we create a utility for checking internet connection, there are two ways we can create this utility, one where the utility emits 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());
    }
}

创建此实用程序的其他方法是,如果连接状态发生变化,该实用程序会继续发出连接状态,如下所示,

Other way of creating this utility is, where the utility keeps emitting the 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();
                });
            }
        });
    }
}

接下来,在您的 dataSource 或 Presenter 中使用 switchMap 或 flatMap 在执行任何网络操作之前​​检查互联网连接,如下所示,

Next, in your dataSource or Presenter use switchMap or flatMap to check for internet connection before doing any network operation which 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;
                    }));
}

请注意,我们使用的是 switchMap 而不是 flatMap.为什么要切换地图?因为,我们这里有 2 个数据流,第一个是互联网连接,第二个是改造.首先我们将获取连接状态值(true/false),如果我们有活动连接,我们将创建一个新的 Retrofit 流并返回开始获取结果,如果连接状态发生变化,switchMap 将首先停止现有的改造连接,然后决定我们是否需要开始一个新的连接或忽略它.

Note that, we are using switchMap instead of flatMap. why switchMap? because, we have 2 data stream here, first is internet connection and second is Retrofit. first we will take connection status value (true/false), if we have active connection, we will create a new Retrofit stream and return start getting results, down the line if we the status of the connection changes, switchMap will first stop the existing Retrofit connection and then decide if we need to start a new one or ignore it.

这是示例之一,可能会更清晰 https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/dataSource/GitHubUserListDataSource.java

This is one of the sample, which might 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

编辑 2:

所以你的意思是切换地图会在互联网恢复后自行尝试?

So you mean switch map will try it itself once internet is back?

Yes 和 No,我们先来看看 flatMap 与否的区别切换地图.假设我们有一个 editText 并且我们根据用户键入的内容从网络中搜索一些信息,每次用户添加新字符时,我们都必须进行新查询(可以通过 debounce 减少),现在有这么多网络调用只有最新的结果很有用,使用 flatMap,我们将收到我们对网络所做的所有调用的所有结果,另一方面,使用 switchMap,在我们进行查询的那一刻, 之前的所有调用都将被丢弃.

Yes and No, let's first see the difference between flatMap & switchMap. Let's say we have an editText and we search some info from network based on what user types, every time user adds a new character we have to make a new query (which can be reduced with debounce), now with so many network calls only the latest results are useful, with flatMap we will receive all the results from all the calls we made to the network, with switchMap on the other hand, the moment we make a query, all previous calls are discarded.

现在这里的解决方案由两部分组成,

Now the solution here is made of 2 parts,

  1. 我们需要一个不断发射网络当前状态的 Observable,上面的第一个 InternetConnection 发送一次状态并调用 onComplete(),但第二个有一个广播接收器,它会在网络连接时继续发送 onNext()状态变化.如果您需要针对案例 2 制定反应式解决方案

  1. We need an Observable that keeps emitting current state of Network, the first InternetConnection above sends the status once and calls onComplete(), but the second one has a Broadcast receiver and it will keep sending onNext() when network status changes. IF you need to make a reactive solution go for case-2

假设您选择 InternetConnection case-2,在这种情况下使用 switchMap(),因为当网络状态发生变化时,我们需要停止 Retrofit 正在做的任何事情,然后根据网络的状态或者做一个新电话或不打电话.

Let's say you choose InternetConnection case-2, in this case use switchMap(), cause when network status changes, we need to stop Retrofit from whatever it is doing and then based on the status of network either make a new call or don't make a call.

我如何让我的观点知道错误是互联网,这是否也可以扩展,因为我需要处理每个网络调用,关于编写包装器的任何建议?

How do I let my view know that the error is internet one also will this be scalable because I need to do with every network call, any suggestions regarding writing a wrapper?

编写包装器将是一个不错的选择,您可以创建自己的自定义响应,该响应可以从一组可能的响应中获取多个条目,例如SUCCESS_INTERNET、SUCCESS_LOGIN、ERROR_INVALID_ID

Writing a wrapper would be excellent choice, you can create your own custom response which can take multiple entries from a set of possible responses e.g. SUCCESS_INTERNET, SUCCESS_LOGIN, ERROR_INVALID_ID

请在此处找到更新的 InternetConnectionUtil https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/util/InternetConnection.java

Please find an 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

关于同一主题的更多细节在这里:https://medium.com/@Viraj.Tank/android-mvp-that-survives-view-life-cycle-configuration-internet-changes-part-2-6b1e2b5c5294

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

我最近使用 Android 架构组件创建了一个 Internet 实用程序 - LiveData,您可以在此处找到完整的源代码,https://github.com/viraj49/Internet-Utitliy-using-AAC-LiveData

I have recently created an Internet utility using Android Architecture Components - LiveData, you can find full source code here, https://github.com/viraj49/Internet-Utitliy-using-AAC-LiveData

代码的详细说明在这里,https://medium.com/@Viraj.Tank/internet-utility-using-android-architecture-components-livedata-e828a0fcd3db

A detailed description of the code is here, https://medium.com/@Viraj.Tank/internet-utility-using-android-architecture-components-livedata-e828a0fcd3db

这篇关于互联网检查,使用MVP、RX和Retrofit时该放在哪里的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆