互联网检查,使用MVP,RX和翻新时的放置位置 [英] Internet check, where to place when using MVP, RX and Retrofit

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

问题描述

我已经通过

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

  • 效率

  • Efficiency

可扩展性

通用:我希望在遵循类似MVP和Repository/DataProvider(可能从网络/数据库提供数据)的体系结构的应用中可以使用相同的逻辑

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检查Internet连接,

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个数据流,第一个是Internet连接,第二个是Retrofit.首先,我们将获取连接状态值(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.

这是示例之一,可以提供更好的清晰度

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

所以您的意思是,一旦互联网恢复正常,切换图将自己尝试一下?

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

是和否,首先让我们看看flatMap和& switchMap.假设我们有一个editText,并根据用户类型从网络中搜索了一些信息,每次用户添加新字符时,我们都必须进行新查询(可以用反跳来减少),现在网络调用太多了,最新的结果很有用,通过 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(),但是第二个InternetConnection具有广播接收器,当网络连接时它将继续发送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

请在此处有关同一主题的更多详细信息,请参见:

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体系结构组件-LiveData创建了一个Internet实用程序,您可以在此处找到完整的源代码, 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和翻新时的放置位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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