MVP结合RxJava以及Retrofit详解

最近在研究Android网络请求的相关框架,目前比较主流的就是RxJava结合Retrofit的使用,看了大神Carson_Ho对该框架的剖析,学习的同时也在此同步记录总结,后面用的时候可以直接查阅此文。

RxJava

RxJava是一个 基于事件流、实现异步操作的库,包含各种各样的操作符,其基于链式的调用方式可以完成丰富的功能需求,使用方便简单,深受大家的喜欢。

在这里,我总结了关于RxJava的多种操作符的使用,通过结合多种操作符即可完成大多数功能需求,这里介绍的类似于API一样的调用方式,每个操作符通过一个小案例实现,并在案例中描述了操作符的具体作用。

创建被观察者
字段特点
create最原始的创建被观察者的方式,最繁琐却能定义最复杂的事件
just快速创建多个事件(小于10个)
fromArray从数组快速创建多个事件(可大于10个)
fromIterable通过集合创建事件(可多个)
empty仅发送Complete事件,直接通知完成
error仅发送Error事件,直接通知异常
never不发送任何事件
defer直到有观察者订阅时,才动态创建被观察者对象 & 发送事件,保证事件是最新的。
timer延迟发送事件
interval,intervalRange周期性发送事件
range发送指定范围的事件
变换事件
字段特点
map将被观察者发送的事件转换为任意的类型事件
flatMap将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列进行发送
concatMap与FlatMap的 区别在于:拆分 & 重新合并生成的事件序列 的顺序 = 被观察者旧序列生产的顺序
buffer定期从 被观察者需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送
组合操作符
字段特点
concat组合多个被观察者(小于4个)一起发送数据,合并后 按发送顺序串行执行
concatArray组合多个被观察者(大于4个)一起发送数据,合并后 按发送顺序串行执行
merge组合多个被观察者(小于4个)一起发送数据,合并后 按时间线并行执行
mergeArray组合多个被观察者(大于4个)一起发送数据,合并后 按时间线并行执行
concatArrayDelayError发生error事件时,等其他被观察者发送完事件之后再发送error事件
zip合并多个被观察者(Observable)发送的事件,生成一个新的事件序列(即组合过后的事件序列),并最终发送
combineLatest与Zip的区别:Zip+ 按个数合并,即1对1合并;CombineLatest = 按时间合并,即在同一个时间点上合并
reduce把被观察者需要发送的事件聚合成1个事件 & 发送
collect将被观察者Observable发送的数据事件收集到一个数据结构里
startWith在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者
count统计被观察者发送事件的数量
功能操作符
字段特点
delay使得被观察者延迟一段时间再发送事件
doOnEach当Observable每发送1次数据事件就会调用1次
doOnNext执行onNext事件前调用,这里已经可以拿到事件结果了
doAfterNext执行onNext事件后调用
doOnCompleteObservable正常发送事件完毕后调用
doOnErrorObservable发送错误事件时调用
doOnSubscribe观察者订阅时调用
doAfterTerminateObservable发送事件完毕后调用,无论正常发送完毕 / 异常终止
doFinally最后执行
onErrorReturn遇到错误时,发送1个特殊事件 & 正常终止
onErrorResumeNext遇到Throwable错误时,发送1个新的Observable
onExceptionResumeNext遇到Exception错误时,发送1个新的Observable
retry接收到 onError()时,重新订阅 & 发送事件
retryWhen遇到error事件才会回调
repeat无条件地、重复发送 被观察者事件
repeatWhen将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者,以此决定是否重新订阅 & 发送原来的 Observable

在实现功能之前可以在此复习一下各操作符,然后结合功能组合操作符,最终实现自己想要的效果。

下面详细讲一下每个字段的使用,在这之前首先说明一下本次使用的RxJava的版本:

implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

引入包之后即可使用RxJava的字段,在这里我写了一个类RxJavaUtil,这里把每个字段的用法都简单写了一下,想体验一下使用效果的直接复制这个类,并在Activity中运行一下即可。这里主要参考的是Carson_Ho大神的RxJava系列讲解文章,再次感谢大佬的无私奉献。


public class RxJavaUtil {
    private static final String TAG = RxJavaUtil.class.getSimpleName();

    // <-----------------------------------创建操作符----------------------------------------------->

    // Integer观察者,定义接收到事件后的处理
    Observer observer = new Observer<Integer>() {
        @Override
        public void onSubscribe(Disposable d) {
            System.out.println("开始采用subscribe连接");
        }

        @Override
        public void onNext(Integer value) {
            System.out.println("接收到了事件"+ value);
        }

        @Override
        public void onError(Throwable e) {
            System.out.println("对Error事件作出响应");
        }

        @Override
        public void onComplete() {
            System.out.println("对Complete事件作出响应");
        }
    };
    
    // Long观察者,延时监听会发送long value
    Observer<Long> longObserver = new Observer<Long>() {
        @Override
        public void onSubscribe(Disposable d) {
            System.out.println("开始采用subscribe连接");
        }

        @Override
        public void onNext(Long value) {
            System.out.println("接收到了事件"+ value);
        }

        @Override
        public void onError(Throwable e) {
            System.out.println("对Error事件作出响应");
        }

        @Override
        public void onComplete() {
            System.out.println("对Complete事件作出响应");
        }
    };

    /**
     * 1.定义好被观察者以及被订阅之后发送的事件
     * 2.定义观察者以及接收到事件后的相应
     * 3.订阅,可多次订阅,多次订阅则多次连接并多次触发响应
     */
    public void createObservableByCreate() {
        Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onComplete();
            }
        });
        observable.subscribe(observer);
    }

    /**
     * 快速创建Observable,与createObservableByCreate方法类似,只是创建Observable更为便捷
     * 创建时传入整型1、2、3、4
     * 在创建后就会发送这些对象,相当于执行了onNext(1)、onNext(2)、onNext(3)、onNext(4)
     *
     * 应用场景:快速创建 被观察者对象(Observable) & 发送10个以下事件
     */
    public void createObservableByJust() {
        // 创建时传入整型1、2、3、4
        // 在创建后就会发送这些对象,相当于执行了onNext(1)、onNext(2)、onNext(3)、onNext(4)
        Observable observable = Observable.just(1, 2, 3,4);
        observable.subscribe(observer);
    }

    /**
     * 通过数组创建Observable,与createObservableByJust类似,但可以传递更多的事件
     *
     * 应用场景:快速创建 被观察者对象(Observable) & 发送10个以上事件
     */
    public void createObservableByArray() {
        Integer[] items = {1,2,3,4,5,6};
        Observable observable = Observable.fromArray(items);
        observable.subscribe(observer);
    }

    /**
     * 通过集合创建Observable,与createObservableByArray类似
     *
     * 应用场景:快速创建 被观察者对象(Observable) & 发送10个以上事件(集合形式)
     */
    public void createObservableByIterable() {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        Observable observable = Observable.fromIterable(list);
        observable.subscribe(observer);
    }

    /**
     * 用来测试的一些Observable
     */
    public void createObservableForTest() {
        // 该方法创建的被观察者对象发送事件的特点:仅发送Complete事件,直接通知完成
        Observable emptyObservable = Observable.empty();
        emptyObservable.subscribe(observer);
        // 该方法创建的被观察者对象发送事件的特点:仅发送Error事件,直接通知异常
        Observable errorObservable = Observable.error(new RuntimeException());
        errorObservable.subscribe(observer);
        // 该方法创建的被观察者对象发送事件的特点:不发送任何事件
        Observable neverObservable = Observable.never();
        neverObservable.subscribe(observer);
    }

    /**
     * 通过 Observable工厂方法创建被观察者对象(Observable)
     * 每次订阅后,都会得到一个刚创建的最新的Observable对象,这可以确保Observable对象里的数据是最新的
     * 直到有观察者(Observer )订阅时,才动态创建被观察者对象(Observable) & 发送事件
     *
     * 因为是在订阅时才创建,所以i值会取第2次的赋值
     */
    int i;
    public void createObservableByDefer() {
        i = 10;
        Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
            @Override
            public ObservableSource<? extends Integer> call() throws Exception {
                return Observable.just(i);
            }
        });
        i = 100;
        observable.subscribe(observer);
    }

    /**
     * 延迟指定时间后,发送1个数值0(Long类型)
     * 本质 = 延迟指定时间后,调用一次 onNext(0)
     */
    public void createObservableByTimer() {
        Observable observable = Observable.timer(2, TimeUnit.SECONDS);
        observable.subscribe(longObserver);
    }

    /**
     * 发送事件的特点:每隔指定时间就发送事件
     * 发送的事件序列 = 从0开始、无限递增1的的整数序列
     */
    public void createObservableByInterval() {
        Observable observable = Observable.interval(1, 1, TimeUnit.SECONDS);
        observable.subscribe(longObserver);
    }

    /**
     * 发送事件的特点:每隔指定时间 就发送 事件,可指定发送的数据的数量
     * a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
     * b. 作用类似于interval(),但可指定发送的数据的数量
     */
    public void createObservableByIntervalRange() {
        // 参数说明:
        // 参数1 = 事件序列起始点;
        // 参数2 = 事件数量;
        // 参数3 = 第1次事件延迟发送时间;
        // 参数4 = 间隔时间数字;
        // 参数5 = 时间单位
        Observable observable = Observable.intervalRange(3, 10, 2, 1, TimeUnit.SECONDS);
        observable.subscribe(longObserver);
    }

    /**
     * 发送事件的特点:连续发送 1个事件序列,可指定范围
     * 作用类似于intervalRange(),但区别在于:无延迟发送事件
     * 还有一个rangeLong方法,与该方法使用一致
     */
    public void createObservableByRange() {
        Observable observable = Observable.range(1, 3);
        observable.subscribe(observer);
    }

    // <----------------------------------------------变换操作符------------------------------------->

    // 接收转换后的事件
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            System.out.println(s);
        }
    };

    /**
     * 对被观察者发送的每1个事件都通过指定的函数处理,从而变换成另外一种事件,即, 将被观察者发送的事件转换为任意的类型事件。
     * 应用场景:数据类型转换
     */
    @SuppressLint("CheckResult")
    public void handleEventByMap() {
        Observable<Integer> observable = Observable.just(1,2,3,4);
        observable.map(new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) throws Exception {
                return "变换前 : " + integer + "变换后" + integer.toString();
            }
        }).subscribe(consumer);
    }

    /**
     * 将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送
     *
     * 应用场景:无序的将被观察者发送的整个事件序列进行变换
     * 新合并生成的事件序列顺序是无序的,即 与旧序列发送事件的顺序无关
     */
    @SuppressLint("CheckResult")
    public void handleEventByFlatMap() {
        Observable<Integer> observable = Observable.just(1,2,3,4);
        observable.flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("我是事件 " + integer + "拆分后的子事件" + i);
                    // 通过flatMap中将被观察者生产的事件序列先进行拆分,再将每个事件转换为一个新的发送三个String事件
                    // 最终合并,再发送给被观察者
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(consumer);
    }

    /**
     * 与FlatMap()的 区别在于:拆分 & 重新合并生成的事件序列 的顺序 = 被观察者旧序列生产的顺序
     * 新合并生成的事件序列顺序是有序的,即 严格按照旧序列发送事件的顺序
     *
     * 应用场景:有序的将被观察者发送的整个事件序列进行变换
     */
    @SuppressLint("CheckResult")
    public void handleEventByConcatMap() {
        Observable<Integer> observable = Observable.just(1,2,3,4);
        observable.concatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("我是事件 " + integer + "拆分后的子事件" + i);
                    // 通过flatMap中将被观察者生产的事件序列先进行拆分,再将每个事件转换为一个新的发送三个String事件
                    // 最终合并,再发送给被观察者
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(consumer);
    }

    /**
     * 定期从 被观察者(Obervable)需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送
     *
     * 应用场景:缓存被观察者发送的事件
     */
    public void handleEventByBuffer() {
        Observable.just(1, 2, 3, 4, 5)
                .buffer(3, 1) // 设置缓存区大小 & 步长
                // 缓存区大小 = 每次从被观察者中获取的事件数量
                // 步长 = 每次获取新事件的数量
                .subscribe(new Observer<List<Integer>>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(List<Integer> stringList) {
                        //
                        System.out.println(" 缓存区里的事件数量 = " +  stringList.size());
                        for (Integer value : stringList) {
                            System.out.println(" 事件 = " + value);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        System.out.println("对Error事件作出响应" );
                    }

                    @Override
                    public void onComplete() {
                        System.out.println("对Complete事件作出响应");
                    }
                });
    }

    // <--------------------------------------------------组合/合并操作符--------------------------------->

    /**
     * 组合多个被观察者一起发送数据,合并后 按发送顺序串行执行
     * 组合被观察者数量≤4个
     */
    public void concatObservable() {
        Observable.concat(Observable.just(1, 2, 3),
                Observable.just(4, 5, 6),
                Observable.just(7, 8, 9),
                Observable.just(10, 11, 12))
                .subscribe(observer);
    }

    /**
     * 组合多个被观察者一起发送数据,合并后 按发送顺序串行执行
     * 组合被观察者数量>4个
     */
    public void concarArrayObservable() {
        Observable.concatArray(Observable.just(1, 2, 3),
                Observable.just(4, 5, 6),
                Observable.just(7, 8, 9),
                Observable.just(10, 11, 12),
                Observable.just(13, 14, 15))
                .subscribe(observer);
    }

    /**
     * 组合多个被观察者一起发送数据,合并后 按时间线并行执行
     * 组合被观察者数量≤4个
     */
    public void mergeObservable() {
        Observable.merge(
                // 从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
                // 从2开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS))
                .subscribe(longObserver);
    }

    /**
     * 组合多个被观察者一起发送数据,合并后 按时间线并行执行
     * 组合被观察者数量>4个
     */
    public void mergeArrayObservable() {
        Observable.mergeArray(
                Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
                Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS),
                Observable.intervalRange(4, 3, 1, 1, TimeUnit.SECONDS),
                Observable.intervalRange(6, 3, 1, 1, TimeUnit.SECONDS),
                Observable.intervalRange(8, 3, 1, 1, TimeUnit.SECONDS),
                Observable.intervalRange(10, 3, 1, 1, TimeUnit.SECONDS))
                .subscribe(longObserver);
    }

    /**
     * 使用concat和merge操作符时
     * 若其中一个Observable发出了onError事件,则会马上终止其他被观察者的事件发送
     * 通过DelayError操作符,可以等其他被观察者发送完事件之后再发送error事件
     *
     * 下面演示了concatArrayDelayError的使用,concatDelayError,mergeDelayError,mergeArrayDelayError,combineLatestDelayError使用相同
     */
    public void concatDelayErrorObservable() {
        Observable.concatArrayDelayError(
                Observable.create(new ObservableOnSubscribe<Integer>() {
                    @Override
                    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {

                        emitter.onNext(1);
                        emitter.onNext(2);
                        emitter.onNext(3);
                        emitter.onError(new NullPointerException()); // 发送Error事件,因为使用了concatDelayError,所以第2个Observable将会发送事件,等发送完毕后,再发送错误事件
                        emitter.onComplete();
                    }
                }),
                Observable.just(4, 5, 6))
                .subscribe(observer);
    }

    /**
     * 合并多个被观察者(Observable)发送的事件,生成一个新的事件序列(即组合过后的事件序列),并最终发送
     *
     * 事件组合方式 = 严格按照原先事件序列 进行对位合并
     * 最终合并的事件数量 = 多个被观察者(Observable)中数量最少的数量
     *
     * 尽管被观察者2的事件D没有事件与其合并,但还是会继续发送
     * 若在被观察者1 & 被观察者2的事件序列最后发送onComplete()事件,则被观察者2的事件D也不会发送
     *
     * 应用场景:合并网络请求的发送,统一显示结果(RxJava+Retrofit)
     */
    public void zipObservable() {
        // <-- 创建第1个被观察者 -->
        Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "被观察者1发送了事件1");
                emitter.onNext(1);
                // 为了方便展示效果,所以在发送事件后加入2s的延迟
                Thread.sleep(1000);

                Log.d(TAG, "被观察者1发送了事件2");
                emitter.onNext(2);
                Thread.sleep(1000);

                Log.d(TAG, "被观察者1发送了事件3");
                emitter.onNext(3);

                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.io()); // 设置被观察者1在工作线程1中工作

        //<-- 创建第2个被观察者 -->
        Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                Log.d(TAG, "被观察者2发送了事件A");
                emitter.onNext("A");
                Thread.sleep(1000);

                Log.d(TAG, "被观察者2发送了事件B");
                emitter.onNext("B");
                Thread.sleep(1000);

                Log.d(TAG, "被观察者2发送了事件C");
                emitter.onNext("C");

                Log.d(TAG, "被观察者2发送了事件D");
                emitter.onNext("D");

                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.newThread());// 设置被观察者2在工作线程2中工作
        // 假设不作线程控制,则该两个被观察者会在同一个线程中工作,即发送事件存在先后顺序,而不是同时发送

        //<-- 使用zip变换操作符进行事件合并 -->
        // 注:创建BiFunction对象传入的第3个参数 = 合并后数据的数据类型
        Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer integer, String string) throws Exception {
                return  integer + string;
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "onSubscribe");
            }

            @Override
            public void onNext(String value) {
                Log.d(TAG, "最终接收到的事件 =  " + value);
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "onError");
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "onComplete");
            }
        });
    }

    /**
     * 当两个Observables中的任何一个发送了数据后,将先发送了数据的Observables 的最新(最后)一个数据与
     * 另外一个Observable发送的每个数据结合,最终基于该函数的结果发送数据
     *
     * 与Zip()的区别:Zip() = 按个数合并,即1对1合并;CombineLatest() = 按时间合并,即在同一个时间点上合并
     */
    @SuppressLint("CheckResult")
    public void conbineLatestObservable() {
        Observable.combineLatest(
                // 第1个发送数据事件的Observable
                Observable.just(1L, 2L, 3L),
                // 第2个发送数据事件的Observable:从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
                new BiFunction<Long, Long, Long>() {
                    @Override
                    public Long apply(Long o1, Long o2) throws Exception {
                        // o1 = 第1个Observable发送的最新(最后)1个数据
                        // o2 = 第2个Observable发送的每1个数据
                        Log.e(TAG, "合并的数据是: "+ o1 + " "+ o2);
                        return o1 + o2;
                        // 合并的逻辑 = 相加
                        // 即第1个Observable发送的最后1个数据 与 第2个Observable发送的每1个数据进行相加
                    }
                }).subscribe(new Consumer<Long>() {
            @Override
            public void accept(Long s) throws Exception {
                Log.e(TAG, "合并的结果是: "+s);
            }
        });
    }

    /**
     * 把被观察者需要发送的事件聚合成1个事件 & 发送
     * 聚合的逻辑根据需求撰写,但本质都是前2个数据聚合,然后与后1个数据继续进行聚合,依次类推
     */
    @SuppressLint("CheckResult")
    public void reduceObservable() {
        Observable.just(1,2,3,4)
                .reduce(new BiFunction<Integer, Integer, Integer>() {
                    // 在该复写方法中复写聚合的逻辑
                    @Override
                    public Integer apply(@NonNull Integer s1, @NonNull Integer s2) throws Exception {
                        Log.e(TAG, "本次计算的数据是: "+s1 +" 乘 "+ s2);
                        return s1 * s2;
                        // 本次聚合的逻辑是:全部数据相乘起来
                        // 原理:第1次取前2个数据相乘,之后每次获取到的数据 = 返回的数据x原始下1个数据每
                    }
                }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(@NonNull Integer s) throws Exception {
                Log.e(TAG, "最终计算的结果是: "+s);

            }
        });
    }

    /**
     * 将被观察者Observable发送的数据事件收集到一个数据结构里
     */
    @SuppressLint("CheckResult")
    public void collectObservable() {
        Observable.just(1, 2, 3 ,4, 5, 6)
                .collect(
                        // 1. 创建数据结构(容器),用于收集被观察者发送的数据
                        new Callable<ArrayList<Integer>>() {
                            @Override
                            public ArrayList<Integer> call() throws Exception {
                                return new ArrayList<>();
                            }
                            // 2. 对发送的数据进行收集
                        }, new BiConsumer<ArrayList<Integer>, Integer>() {
                            @Override
                            public void accept(ArrayList<Integer> list, Integer integer)
                                    throws Exception {
                                // 参数说明:list = 容器,integer = 后者数据
                                list.add(integer);
                                // 对发送的数据进行收集
                            }
                        }).subscribe(new Consumer<ArrayList<Integer>>() {
            @Override
            public void accept(@NonNull ArrayList<Integer> s) throws Exception {
                Log.e(TAG, "本次发送的数据是: "+s);

            }
        });
    }

    /**
     * 在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者
     */
    public void startWithObservable() {
        // <-- 在一个被观察者发送事件前,追加发送一些数据 -->
        // 注:追加数据顺序 = 后调用先追加
        Observable.just(4, 5, 6)
                .startWith(0)  // 追加单个数据 = startWith()
                .startWithArray(1, 2, 3) // 追加多个数据 = startWithArray()
                .subscribe(observer);


        // <-- 在一个被观察者发送事件前,追加发送被观察者 & 发送数据 -->
        // 注:追加数据顺序 = 后调用先追加
        Observable.just(4, 5, 6)
                .startWith(Observable.just(1, 2, 3))
                .subscribe(observer);
    }

    /**
     * 统计被观察者发送事件的数量
     */
    @SuppressLint("CheckResult")
    public void countEvent() {
        Observable.just(1, 2, 3, 4)
                .count()
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Log.e(TAG, "发送的事件数量 =  "+aLong);

                    }
                });
    }

    // <--------------------------------------------------功能操作符--------------------------------->
    /**
     * 使得被观察者延迟一段时间再发送事件
     */
    public void delaySendEvent() {
        // 指定延迟时间 & 调度器 & 错误延迟
        // 参数1 = 延迟时间;参数2 = 时间单位;参数3 = 线程调度器;参数4 = 错误通知是否延迟
        Observable.just(1, 2, 3)
                .delay(3, TimeUnit.SECONDS, Schedulers.newThread(), true) // 延迟3s再发送,由于使用类似,所以此处不作全部展示
                .subscribe(observer);
    }

    /**
     * 在某个事件的生命周期中调用
     */
    public void doOnObservable() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onNext(3);
                e.onError(new Throwable("发生错误了"));
            }
        })
                // 1. 当Observable每发送1次数据事件就会调用1次
                .doOnEach(new Consumer<Notification<Integer>>() {
                    @Override
                    public void accept(Notification<Integer> integerNotification) throws Exception {
                        Log.d(TAG, "doOnEach: " + integerNotification.getValue());
                    }
                })
                // 2. 执行onNext事件前调用,这里已经可以拿到事件结果了
                .doOnNext(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.d(TAG, "doOnNext: " + integer);
                    }
                })
                // 3. 执行onNext事件后调用
                .doAfterNext(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.d(TAG, "doAfterNext: " + integer);
                    }
                })
                // 4. Observable正常发送事件完毕后调用
                .doOnComplete(new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.e(TAG, "doOnComplete: ");
                    }
                })
                // 5. Observable发送错误事件时调用
                .doOnError(new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.d(TAG, "doOnError: " + throwable.getMessage());
                    }
                })
                // 6. 观察者订阅时调用
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(@NonNull Disposable disposable) throws Exception {
                        Log.e(TAG, "doOnSubscribe: ");
                    }
                })
                // 7. Observable发送事件完毕后调用,无论正常发送完毕 / 异常终止
                .doAfterTerminate(new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.e(TAG, "doAfterTerminate: ");
                    }
                })
                // 8. 最后执行
                .doFinally(new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.e(TAG, "doFinally: ");
                    }
                })
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(Integer value) {
                        Log.d(TAG, "接收到了事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "对Complete事件作出响应");
                    }
                });
    }

    /**
     * 遇到错误时,发送1个特殊事件 & 正常终止
     */
    public void onErrorReturn() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onError(new Throwable("发生错误了"));
            }
        })
                .onErrorReturn(new Function<Throwable, Integer>() {
                    @Override
                    public Integer apply(@NonNull Throwable throwable) throws Exception {
                        // 捕捉错误异常
                        Log.e(TAG, "在onErrorReturn处理了错误: "+throwable.toString() );

                        return 666;
                        // 发生错误事件后,发送一个"666"事件,最终正常结束
                    }
                })
                .subscribe(observer);
    }

    /**
     * 遇到错误时,发送1个新的Observable
     *
     *  onErrorResumeNext()拦截的错误 = Throwable;若需拦截Exception请用onExceptionResumeNext()
     *  若onErrorResumeNext()拦截的错误 = Exception,则会将错误传递给观察者的onError方法
     */
    public void onErrorResumeNext() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onError(new Throwable("发生错误了"));
            }
        })
                .onErrorResumeNext(new Function<Throwable, ObservableSource<? extends Integer>>() {
                    @Override
                    public ObservableSource<? extends Integer> apply(@NonNull Throwable throwable) throws Exception {
                        // 1. 捕捉错误异常
                        Log.e(TAG, "在onErrorReturn处理了错误: "+throwable.toString() );
                        // 2. 发生错误事件后,发送一个新的被观察者 & 发送事件序列
                        return Observable.just(11,22);

                    }
                })
                .subscribe(observer);
    }

    /**
     * 遇到错误时,发送1个新的Observable
     *
     *  onExceptionResumeNext()拦截的错误 = Exception;若需拦截Throwable请用onErrorResumeNext()
     *  若onExceptionResumeNext()拦截的错误 = Throwable,则会将错误传递给观察者的onError方法
     */
    public void onExceptionResumeNext() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onError(new Exception("发生错误了"));
            }
        })
                .onExceptionResumeNext(new Observable<Integer>() {
                    @Override
                    protected void subscribeActual(Observer<? super Integer> observer) {
                        observer.onNext(11);
                        observer.onNext(22);
                        observer.onComplete();
                    }
                })
                .subscribe(observer);
    }

    /**
     * 重试,即当出现错误时,让被观察者(Observable)重新发射数据
     * 接收到 onError()时,重新订阅 & 发送事件
     * Throwable 和 Exception都可拦截
     *
     * 共五种重载方法
     * <-- 1. retry() -->
     * // 作用:出现错误时,让被观察者重新发送数据
     * // 注:若一直错误,则一直重新发送
     *
     * <-- 2. retry(long time) -->
     * // 作用:出现错误时,让被观察者重新发送数据(具备重试次数限制
     * // 参数 = 重试次数
     *
     * <-- 3. retry(Predicate predicate) -->
     * // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送& 持续遇到错误,则持续重试)
     * // 参数 = 判断逻辑
     *
     * <--  4. retry(new BiPredicate<Integer, Throwable>) -->
     * // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送 & 持续遇到错误,则持续重试
     * // 参数 =  判断逻辑(传入当前重试次数 & 异常错误信息)
     *
     * <-- 5. retry(long time,Predicate predicate) -->
     * // 作用:出现错误后,判断是否需要重新发送数据(具备重试次数限制
     * // 参数 = 设置重试次数 & 判断逻辑
     *
     * retryUntil()
     * 具体使用类似于retry(Predicate predicate),唯一区别:返回 true 则不重新发送数据事件。
     */
    public void retry() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onError(new Exception("发生错误了"));
                e.onNext(3);
            }
        })

                // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送 & 持续遇到错误,则持续重试
                // 参数 =  判断逻辑(传入当前重试次数 & 异常错误信息)
                .retry(new BiPredicate<Integer, Throwable>() {
                    @Override
                    public boolean test(@NonNull Integer integer, @NonNull Throwable throwable) throws Exception {
                        // 捕获异常
                        Log.e(TAG, "异常错误 =  "+throwable.toString());

                        // 获取当前重试次数
                        Log.e(TAG, "当前重试次数 =  "+integer);

                        //返回false = 不重新重新发送数据 & 调用观察者的onError结束
                        //返回true = 重新发送请求(若持续遇到错误,就持续重新发送)
                        return true;
                    }
                })
                .subscribe(observer);
    }

    /**
     * 遇到错误时,将发生的错误传递给一个新的被观察者(Observable),并决定是否需要重新订阅原始被观察者(Observable)& 发送事件
     */
    public void retryWhen() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onError(new Exception("发生错误了"));
                e.onNext(3);
            }
        })
                // 遇到error事件才会回调
                .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {

                    @Override
                    public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
                        // 参数Observable<Throwable>中的泛型 = 上游操作符抛出的异常,可通过该条件来判断异常的类型
                        // 返回Observable<?> = 新的被观察者 Observable(任意类型)
                        // 此处有两种情况:
                        // 1. 若 新的被观察者 Observable发送的事件 = Error事件,那么 原始Observable则不重新发送事件:
                        // 2. 若 新的被观察者 Observable发送的事件 = Next事件 ,那么原始的Observable则重新发送事件:
                        return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                            @Override
                            public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {

                                // 1. 若返回的Observable发送的事件 = Error事件,则原始的Observable不重新发送事件
                                // 该异常错误信息可在观察者中的onError()中获得
                                return Observable.error(new Throwable("retryWhen终止啦"));

                                // 2. 若返回的Observable发送的事件 = Next事件,则原始的Observable重新发送事件(若持续遇到错误,则持续重试)
                                // return Observable.just(1);
                            }
                        });

                    }
                })
                .subscribe(observer);
    }

    /**
     * 无条件地、重复发送 被观察者事件
     */
    public void repeat() {
        Observable.just(1, 2, 3, 4)
                .repeat(3) // 重复创建次数 =- 3次
                .subscribe(observer);
    }

    /**
     * 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable),以此决定是否重新订阅 & 发送原来的 Observable
     *
     * 若新被观察者(Observable)返回1个Complete / Error事件,则不重新订阅 & 发送原来的 Observable
     * 若新被观察者(Observable)返回其余事件时,则重新订阅 & 发送原来的 Observable
     */
    public void repeatWhen() {
        Observable.just(1,2,4).repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
            @Override
            // 在Function函数中,必须对输入的 Observable<Object>进行处理,这里我们使用的是flatMap操作符接收上游的数据
            public ObservableSource<?> apply(@NonNull Observable<Object> objectObservable) throws Exception {
                // 将原始 Observable 停止发送事件的标识(Complete() /  Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable)
                // 以此决定是否重新订阅 & 发送原来的 Observable
                // 此处有2种情况:
                // 1. 若新被观察者(Observable)返回1个Complete() /  Error()事件,则不重新订阅 & 发送原来的 Observable
                // 2. 若新被观察者(Observable)返回其余事件,则重新订阅 & 发送原来的 Observable
                return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(@NonNull Object throwable) throws Exception {

                        // 情况1:若新被观察者(Observable)返回1个Complete() /  Error()事件,则不重新订阅 & 发送原来的 Observable
                        return Observable.empty();
                        // Observable.empty() = 发送Complete事件,但不会回调观察者的onComplete()

                        // return Observable.error(new Throwable("不再重新订阅事件"));
                        // 返回Error事件 = 回调onError()事件,并接收传过去的错误信息。

                        // 情况2:若新被观察者(Observable)返回其余事件,则重新订阅 & 发送原来的 Observable
                        // return Observable.just(1);
                        // 仅仅是作为1个触发重新订阅被观察者的通知,发送的是什么数据并不重要,只要不是Complete() /  Error()事件
                    }
                });

            }
        })
                .subscribe(observer);
    }
}

代码中为了少写点儿代码,很多地方是复用的Observer,但其实RxJava更多的用法是链式调用,在实际使用中可以结合各种字段并链式调用,但要注意调用时候的顺序,否则也容易出现各种意想不到的结果,比如线程错乱等。而且RxJava的魅力也在于其各种字段的链式组合,如果想要掌握RxJava,一定要各种字段的组合都尝试一遍,这样才能得心应手,否则拿到开发需求的时候,仅仅掌握各种字段用法,但不知如何组合调用,也是白学。

Retrofit

好了,RxJava的代码告一段落,下面讲一下Retrofit的使用,毕竟本文的最终目的是实现MVP+RxJava+Retrofit的结合。

Retrofit基于okhttp封装的网络请求框架, 网络请求的工作本质上是 OkHttp 完成,而 retrofit 仅负责网络请求接口的封装。

Retrofit优势,就是简洁易用,解耦,扩展性强,可搭配多种Json解析框架(例如Gson),另外还支持RxJava。

其他关于Retrofit的介绍在这里就不啰嗦了,百度一大堆,这里直接讲干货(Retrofit的使用)

首先引入Retrofit和Gson的支持,这样就可以使用Retrofit的方法以及Gson格式解析了。

implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'

Retrofit毕竟是网络请求,所以需要找一个可以发起网络请求并返回的网站,这里用采用有道翻译,无需注册开发者,直接可用。具体使用可以分为三步:

  1. 编写实体类,用于返回数据的解析
  2. 编写网络请求接口
  3. 通过Retrofit发起网络请求

下面简单讲解一下每一步,不详细描述,具体自行百度即可。

实体类

网络请求的返回结果一般是遵从某种格式的,比如json,xml,protobuff等,而实体类的编写就是为了将这些格式的结果转化,通过Adapter适配器可以将原始格式转化为我们的实体类,方便在程序中访问调用。

有道翻译的返回结果是Gson格式:

{
	"type": "EN2ZH_CN",
	"errorCode": 0,
	"elapsedTime": 1,
	"translateResult": [
		[{
			"src": "hello, world",
			"tgt": "你好,世界"
		}]
	]
}

我们编写一个对应的实体类Translation

public class Translation {
    private static final String TAG = Translation.class.getSimpleName();

    private String type;
    private int errorCode;
    private int elapsedTime;
    private List<List<TranslateResultBean>> translateResult;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }

    public int getElapsedTime() {
        return elapsedTime;
    }

    public void setElapsedTime(int elapsedTime) {
        this.elapsedTime = elapsedTime;
    }

    public List<List<TranslateResultBean>> getTranslateResult() {
        return translateResult;
    }

    public void setTranslateResult(List<List<TranslateResultBean>> translateResult) {
        this.translateResult = translateResult;
    }

    public static class TranslateResultBean {
        public String src;
        public String tgt;

        public String getSrc() {
            return src;
        }

        public void setSrc(String src) {
            this.src = src;
        }

        public String getTgt() {
            return tgt;
        }

        public void setTgt(String tgt) {
            this.tgt = tgt;
        }
    }

    //定义 输出返回数据 的方法
    public void show() {
        Log.d(TAG, type);
        Log.d(TAG, errorCode + "");
        Log.d(TAG, elapsedTime + "");
        Log.d(TAG, translateResult.get(0).get(0).src + ":" + translateResult.get(0).get(0).tgt);
    }

    @Override
    public String toString() {
        return "Translation{" +
                "type='" + type + '\'' +
                ", errorCode=" + errorCode +
                ", elapsedTime=" + elapsedTime +
                ", translateResult=" + translateResult.get(0).get(0).tgt +
                '}';
    }
}

网络请求接口

通过标签来编写网络请求接口,标签众多,这里将用的比较多的标签列举了一遍,并在代码中做了详细说明。其他标签需要用到的时候可以自行查阅,用法一致,不多赘述。

public interface IGetRequest {

    /**
     * Retrofit把网络请求的URL分成了两部分:一部分放在Retrofit对象里,另一部分放在网络请求接口里
     * 如果接口里的url是一个完整的网址,那么放在Retrofit对象里的URL可以忽略
     * getCall()是接受网络请求数据的方法
     *
     * 这里等同于 @GET("translate?doctype=json&type=AUTO&i=keyword")
     * @Path 标签可以动态设置url路径中的信息, @Query标签可以动态设置Get请求的参数信息
     */
    @GET("{translate}?doctype=json&type=AUTO")
    Call<Translation> getCall(@Path("translate") String translate, @Query("i") String keyword);

    /**
     * 这里与上面不同的地方在于字段采用map的方式填充,上面用Query的方式是一个字段一个字段的填充
     * 如果@Get标签后没有跟url,可以在参数中动态设置url,这样的接口具有很大的通用性
     */
    @GET
    Call<Translation> getCall(@Url String url,  @QueryMap HashMap<String, String> map);

    /**
     * 通过Post发送请求,用法与Get类似,只不过把标签换成了@Field
     */
    @POST("translate")
    @FormUrlEncoded
    Call<Translation> postCall(@Field("doctype") String docType, @Field("type") String type, @Field("i") String i);

    @POST("translate")
    @FormUrlEncoded
    Call<Translation> postCall(@FieldMap HashMap<String, String> map);

    /**
     * 替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用及更多功能拓展
     *
     * method:网络请求的方法(区分大小写)
     * path:网络请求地址路径
     * hasBody:是否有请求体
     */
    @HTTP(method = "GET", path = "{translate}?doctype=json&type=AUTO&i=keyword", hasBody = false)
    Call<Translation> httpCall(@Path("translate") String translate);
}
Retrofit请求

Retrofit的主要工作是配置网络请求的参数,包括请求地址,结果适配器,请求参数,结果处理回调等。需要注意,这里的参数配置要与网络请求接口配合,具体需要什么参数,怎么输入参数都是在接口中定义好的,Retrofit中的参数配置更多是执行接口的定义,所以接口的定义至关重要,这里举几个例子说明一下详细用法。

/**
     * Get请求,异步返回,这里用Query标签填充字段
     */
    private void getQueryRequestByCallback() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        IGetRequest request = retrofit.create(IGetRequest.class);
        request.getCall("translate", "中国").enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                response.body().show();
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                Log.e(TAG, t.getMessage() + "连接失败");
            }
        });
    }

    /**
     * Get请求,异步返回,这里用QueryMap标签填充字段
     */
    private void getQueryMapRequestByCallback() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        IGetRequest request = retrofit.create(IGetRequest.class);
        HashMap<String, String> map = new HashMap<>();
        map.put("doctype", "json");
        map.put("type", "AUTO");
        map.put("i", "美国");
        request.getCall("translate", map).enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                response.body().show();
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                Log.e(TAG, "连接失败");
            }
        });
    }

    /**
     * Post请求,异步返回,这里用Field标签填充字段,用法与Get类似
     */
    private void postFieldRequestByCallback() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        IGetRequest request = retrofit.create(IGetRequest.class);
        Call<Translation> call = request.postCall("json", "AUTO", "韩国");
        call.enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                response.body().show();
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                Log.e(TAG, "连接失败");
            }
        });
    }

    /**
     * Get请求,异步返回,这里用FieldMap标签填充字段,用法与Get类似
     */
    private void postFieldMapByCallback() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/")
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        HashMap<String, String> map = new HashMap<>();
        map.put("doctype", "json");
        map.put("type", "AUTO");
        map.put("i", "日本");
        IGetRequest call = retrofit.create(IGetRequest.class);
        call.postCall(map).enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                response.body().show();
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                Log.e(TAG, "连接失败");
            }
        });
    }

    /**
     * 通过http标签发起请求
     */
    private void httpRequestByCallback() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        IGetRequest request = retrofit.create(IGetRequest.class);
        request.httpCall("translate").enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                response.body().show();
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                Log.e(TAG, "连接失败");
            }
        });
    }

    /**
     * 同步返回,其他用法类似,不再举例
     */
    private void postFieldMapBySync() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/")
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        HashMap<String, String> map = new HashMap<>();
        map.put("doctype", "json");
        map.put("type", "AUTO");
        map.put("i", "日本");
        IGetRequest call = retrofit.create(IGetRequest.class);
        try {
            Response<Translation> response = call.postCall(map).execute();
            response.body().show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

至此,RxJava和Retrofit的基础使用基本讲完了,下面进入本文的最终目标,MVP+Retrofit+RxJava结合案例。

MVP+RxJava+Retrofit

案例也很简单,采用的还是有道的网络请求,实现的也就是翻译功能,需求如下:

  • 正常输入文本,可以自动识别出中英文并自动翻译出结果
  • 网络请求失败时,自动重连并发起请求,并避免无限重连,有合理的重连机制
  • 在重连时通过缓冲条展示,避免界面处于无反应状态
  • 多次请求失败后,给出失败原因

MVP应该也不需要介绍,也没啥好说的,直接上代码吧:
首先要引入各种支持

// 此处一定要注意使用RxJava2的版本
    implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

// Android 支持 Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.1.0'

// 衔接 Retrofit & RxJava
// 此处一定要注意使用RxJava2的版本
    implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

// 支持Gson解析
    implementation 'com.squareup.retrofit2:converter-gson:2.1.0'

看一下项目目录
在这里插入图片描述

Translation

这个在上面已经写过了,和上面的一样,就不说了

model

总共就三个类,IMvpModel定义获取网络请求的接口

public interface IMvpModel {
    void getTranslation(String keyword, OnResultCallback callback);
}

MvpModelImpl是IMvpModel的实现,通过Retrofit和RxJava的结合获取网络请求结果,其中也处理了网络请求的重连机制以及重连时的UI缓冲机制,具体的细节可以自己运行调试一下,并没有什么复杂的逻辑。

public class MvpModelImpl implements IMvpModel {
    private static final String TAG = MvpModelImpl.class.getSimpleName();
    private static final String URL_YOUDAO = "http://fanyi.youdao.com/";
    Retrofit retrofit;
    int maxConnectCount = 5;    // 可重试次数
    int currentRetryCount = 0;    // 当前已重试次数
    int waitRetryTime = 0;    // 重试等待时间

    public MvpModelImpl() {
        this.retrofit = RetrofitFactory.getInstance().createRetrofit(URL_YOUDAO);
    }

    @Override
    public void getTranslation(String keyword, final OnResultCallback callback) {
        retrofit.create(IGetRequest.class)
                .getResult(keyword)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
                // 参数Observable<Throwable>中的泛型 = 上游操作符抛出的异常,可通过该条件来判断异常的类型
                return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {
                        Log.d(TAG,  "发生异常 = "+ throwable.toString());
                        if (throwable instanceof IOException){
                            Log.d(TAG,  "属于IO异常,需重试" );
                            if (currentRetryCount < maxConnectCount){
                                // 记录重试次数
                                currentRetryCount++;
                                Log.d(TAG,  "重试次数 = " + currentRetryCount);
                                // 设置等待时间
                                waitRetryTime = 1000 + currentRetryCount* 1000;
                                Log.d(TAG,  "等待时间 =" + waitRetryTime);
                                // 通知UI展示缓冲条
                                callback.onRetryed(currentRetryCount);
                                return Observable.just(1).delay(waitRetryTime, TimeUnit.MILLISECONDS);
                            }else{
                                // 若重试次数已 > 设置重试次数,则不重试
                                // 通过发送error来停止重试(可在观察者的onError()中获取信息)
                                return Observable.error(new Throwable("重试次数已超过设置次数 = " +currentRetryCount  + ",不再重试"));
                            }
                        }
                        // 若发生的异常不属于I/O异常,则不重试
                        // 通过返回的Observable发送的事件 = Error事件 实现(可在观察者的onError()中获取信息)
                        else{
                            return Observable.error(new Throwable("发生了非网络异常(非I/O异常)"));
                        }
                    }
                });
            }
        }).subscribeOn(Schedulers.io())               // 切换到IO线程进行网络请求
                .observeOn(AndroidSchedulers.mainThread())  // 切换回到主线程 处理请求结果
                .subscribe(new Observer<Translation>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(Translation result) {
                    	// 通知界面显示结果
                        callback.onSuccess(result);
                    }

                    @Override
                    public void onError(Throwable e) {
                    	// 通知界面请求失败
                        callback.onError(e);
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }
}
/**
 * 与Presenter层交互的接口
 */
public interface OnResultCallback {
	// 请求成功
    void onSuccess(Translation translation);
	// 尝试重连
    void onRetryed(int count);
	// 请求失败
    void onError(Throwable throwable);
}
Presenter

很简单,View和Model层的衔接,没啥好说的

public interface IMvpPresenter {
    void getTranslation(String keyword);
}
public class MvpPresenterImpl implements IMvpPresenter {
    private static final String TAG = MvpPresenterImpl.class.getSimpleName();
    private IMvpModel model;
    private IView view;

    public MvpPresenterImpl(IView view) {
        this.view = view;
        this.model = new MvpModelImpl();
    }

    @Override
    public void getTranslation(String keyword) {
        model.getTranslation(keyword, new OnResultCallback() {
            @Override
            public void onSuccess(Translation translation) {
                view.showResult(translation);
            }

            @Override
            public void onRetryed(int count) {
                Log.d(TAG, "onRetryed: 重试了" + count + "次了");
                view.showProgress(true);
            }

            @Override
            public void onError(Throwable throwable) {
                Log.e(TAG, "onError: " + throwable.getMessage() );
                view.showError(throwable);
            }
        });
    }
}
View
public interface IView {
    void showResult(Translation result);

    void showError(Throwable throwable);

    void showProgress(boolean isShow);
}
public class MvpActivity extends AppCompatActivity implements IView, View.OnClickListener {
    private static final String TAG = MvpActivity.class.getSimpleName();
    private IMvpPresenter presenter;
    private Button testBt;
    private EditText contextEdit;
    private TextView tv_result;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvp);
        initData();
        initView();
    }
    
    @SuppressLint("HandlerLeak")
    private void initData() {
        presenter = new MvpPresenterImpl(this);
    }

    private void initView() {
        testBt = findViewById(R.id.bt_test);
        testBt.setOnClickListener(this);
        contextEdit = findViewById(R.id.edit_context);
        tv_result = findViewById(R.id.tv_result);
        progressBar = findViewById(R.id.progress_bar);
    }

    @Override
    public void showResult(Translation result) {
        tv_result.setText("翻译结果 : " + result.getTranslateResult().get(0).get(0).getTgt());
        showProgress(false);
    }

    @Override
    public void showError(Throwable throwable) {
        tv_result.setText("获取翻译结果失败,请检查网络是否连接正常!");
        showProgress(false);
    }

    @Override
    public void showProgress(boolean isShow) {
        progressBar.setVisibility(isShow ? View.VISIBLE : View.GONE);

    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_test:
                presenter.getTranslation(contextEdit.getText().toString());
                break;
        }
    }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.skydianshi.mvp.view.MvpActivity">

    <Button
        android:id="@+id/bt_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始翻译"/>

    <EditText
        android:id="@+id/edit_context"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请在此处输入要翻译的文本"
        android:layout_marginTop="20dp"/>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="翻译结果:"
        android:textSize="24sp"
        android:layout_marginTop="20dp"/>

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:indeterminate="false"
        android:visibility="gone"/>

</LinearLayout>

Retrofit

Retrofit的请求接口,跟上面讲Retrofit的时候讲的差不多

public interface IGetRequest {
    @GET("translate?doctype=json&type=AUTO")
    Observable<Translation> getResult(@Query("i") String i);
}

Retrofit工厂类

public class RetrofitFactory {
    private static RetrofitFactory retrofitFactory;

    public static RetrofitFactory getInstance() {
        if (retrofitFactory == null) {
            synchronized (RetrofitFactory.class) {
                if (retrofitFactory == null) {
                    retrofitFactory = new RetrofitFactory();
                }
            }
        }
        return retrofitFactory;
    }

    public Retrofit createRetrofit(String url) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        return retrofit;
    }
}
总结

好了,至此本文基本结束了,总结一下,总共讲了以下几点:

  • RxJava的基本使用
  • Retrofit的基本使用
  • MVP+RxJava+Retrofit的简单案例

之前项目中用的都是MVVM的架构,这次改用MVP来结合还有点不适应,需要定义的接口比较多,但总体感觉逻辑还是清晰一些的,由于不熟悉,文中定有诸多错误,但从实现功能的角度上来看算是完成了最初的设想,适合初学者速成,但要精通还需很多的沉淀。但从目前主流应用来看,主要的应用场景也就是本文所说的网络请求,因此把网络请求这方面理通理顺,应对普通的开发应该还是足够的,希望本文能对你有所帮助。

也希望大佬能不吝赐教文中的有误之处,感谢!

最后看一下demo的效果吧!

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值