【Android学习】RxJava

资料连接

Android RxJava: 这是一份全面的 操作符 使用汇总 (含详细实例讲解)

1. Merge & Zip操作符: 合并数据源

Android RxJava应用:合并数据源
在这里插入图片描述

2. Map & FlapMap & ConcatMap & Buffer: 变换操作符

Android RxJava应用:变换操作符
在这里插入图片描述

3. retry & retryUntil & retryWhen : 错误处理操作符

  • retry
    retry(): 让被观察者重新发射数据,要是一直错误就一直发送了
    retry(BiPredicate): interger是第几次重新发送,Throwable是错误的内容
    retry(long time): 最多让被观察者重新发射数据多少次
    retry(long time,Predicate predicate): 最多让被观察者重新发射数据多少次,在predicate里面进行判断拦截 返回是否继续
    retry(Predicate predicate): 在predicate里面进行判断拦截 返回是否继续
  • retryUntil
    具体使用类似于retry(Predicate predicate),唯一区别:返回 true 则不重新发送数据事件。此处不作过多描述
  • retryWhen
  • 遇到错误时,将发生的错误传递给一个新的被观察者(Observable),并决定是否需要重新订阅原始被观察者(Observable)& 发送事件
    注意:
    retryWhen 通过 flatMap 返回的 Observable.just(1) 仅仅作为一个信号(同样会被onNext方法捕获),触发了原始的 Observable 重新订阅,从而重新执行 onNext(1) 和 onNext(2)
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(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事件作出响应" + e.toString());
                        // 获取异常错误信息
                    }

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

4. Transformer & Compose 转换操作符

Transformer 在RxJava中的使用

  • 定义
    Transformer 是一个接口,用于创建一个操作符,可以将一个 Observable 转换为另一个 Observable。通常,Transformer 是通过实现 ObservableTransformer<T, R> 接口来创建的。
  • 使用场景
    当你需要在多个地方重用相同的操作链时,使用 Transformer 可以将一系列操作封装成一个可复用的单元。
  • 代码
public class MyTransformer<T> implements ObservableTransformer<T, T> {
    @Override
    public ObservableSource<T> apply(Observable<T> upstream) {
        return upstream
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map(value -> value + " transformed");
    }
}

// 使用
observable.compose(new MyTransformer<>()).subscribe(...);

在这里插入图片描述

5. 网络请求嵌套回调 FlatMap

网络请求嵌套回调
场景:需要进行嵌套网络请求:即在第1个网络请求成功后,继续再进行一次网络请求
解决方案:在第一个请求doOnNext方法后,flatMap 发起第二个请求

public class MainActivity extends AppCompatActivity {

        private static final String TAG = "Rxjava";
        // 定义Observable接口类型的网络请求对象
        Observable<Translation1> observable1;
        Observable<Translation2> observable2;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            // 步骤1:创建Retrofit对象
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
                    .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
                    .build();

            // 步骤2:创建 网络请求接口 的实例
            GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

            // 步骤3:采用Observable<...>形式 对 2个网络请求 进行封装
            observable1 = request.getCall();
            observable2 = request.getCall_2();


            observable1.subscribeOn(Schedulers.io())               // (初始被观察者)切换到IO线程进行网络请求1
                       .observeOn(AndroidSchedulers.mainThread())  // (新观察者)切换到主线程 处理网络请求1的结果
                       .doOnNext(new Consumer<Translation1>() {
                        @Override
                        public void accept(Translation1 result) throws Exception {
                            Log.d(TAG, "第1次网络请求成功");
                            result.show();
                            // 对第1次网络请求返回的结果进行操作 = 显示翻译结果
                        }
                    })

                    .observeOn(Schedulers.io())                 // (新被观察者,同时也是新观察者)切换到IO线程去发起登录请求
                                                                // 特别注意:因为flatMap是对初始被观察者作变换,所以对于旧被观察者,它是新观察者,所以通过observeOn切换线程
                                                                // 但对于初始观察者,它则是新的被观察者
                    .flatMap(new Function<Translation1, ObservableSource<Translation2>>() { // 作变换,即作嵌套网络请求
                        @Override
                        public ObservableSource<Translation2> apply(Translation1 result) throws Exception {
                            // 将网络请求1转换成网络请求2,即发送网络请求2
                            return observable2;
                        }
                    })

                    .observeOn(AndroidSchedulers.mainThread())  // (初始观察者)切换到主线程 处理网络请求2的结果
                    .subscribe(new Consumer<Translation2>() {
                        @Override
                        public void accept(Translation2 result) throws Exception {
                            Log.d(TAG, "第2次网络请求成功");
                            result.show();
                            // 对第2次网络请求返回的结果进行操作 = 显示翻译结果
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            System.out.println("登录失败");
                        }
                    });
    }
}

6. 网络请求出错重连 Retrywhen

网络请求出错重连

public class RxJavafixRetrofit2 extends AppCompatActivity {

    private static final String TAG = "RxJava";

    // 设置变量
    // 可重试次数
    private int maxConnectCount = 10;
    // 当前已重试次数
    private int currentRetryCount = 0;
    // 重试等待时间
    private int waitRetryTime = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 步骤1:创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
                .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
                .build();

        // 步骤2:创建 网络请求接口 的实例
        GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

        // 步骤3:采用Observable<...>形式 对 网络请求 进行封装
        Observable<Translation> observable = request.getCall();

        // 步骤4:发送网络请求 & 通过retryWhen()进行重试
        // 注:主要异常才会回调retryWhen()进行重试
        observable.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());

                        /**
                         * 需求1:根据异常类型选择是否重试
                         * 即,当发生的异常 = 网络异常 = IO异常 才选择重试
                         */
                        if (throwable instanceof IOException){

                            Log.d(TAG,  "属于IO异常,需重试" );

                            /**
                             * 需求2:限制重试次数
                             * 即,当已重试次数 < 设置的重试次数,才选择重试
                             */
                            if (currentRetryCount < maxConnectCount){

                                // 记录重试次数
                                currentRetryCount++;
                                Log.d(TAG,  "重试次数 = " + currentRetryCount);

                                /**
                                 * 需求2:实现重试
                                 * 通过返回的Observable发送的事件 = Next事件,从而使得retryWhen()重订阅,最终实现重试功能
                                 *
                                 * 需求3:延迟1段时间再重试
                                 * 采用delay操作符 = 延迟一段时间发送,以实现重试间隔设置
                                 *
                                 * 需求4:遇到的异常越多,时间越长
                                 * 在delay操作符的等待时间内设置 = 每重试1次,增多延迟重试时间1s
                                 */
                                // 设置等待时间
                                waitRetryTime = 1000 + currentRetryCount* 1000;
                                Log.d(TAG,  "等待时间 =" + waitRetryTime);
                                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) {
                        // 接收服务器返回的数据
                        Log.d(TAG,  "发送成功");
                        result.show();
                    }

                    @Override
                    public void onError(Throwable e) {
                        // 获取停止重试的信息
                        Log.d(TAG,  e.toString());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }
}

7. Concat & Merge 组合操作符

组合/合并操作符
在这里插入图片描述

8. 创建操作符

创建操作符

  • 8.1 just
    快速创建1个被观察者对象(Observable)
    发送事件的特点:直接发送 传入的事件
    注:最多只能发送10个参数
  • 8.2 fromArray
    快速创建1个被观察者对象(Observable)
    发送事件的特点:直接发送 传入的数组数据
    注:会将数组中的数据转换为Observable对象
  • 8.3 fromIterable
    快速创建1个被观察者对象(Observable)
    发送事件的特点:直接发送 传入的集合List数据
    应用场景:
    快速创建 被观察者对象(Observable) & 发送10个以上事件(集合形式)
    集合元素遍历
  • 8.4 defer
    直到有观察者(Observer )订阅时,才动态创建被观察者对象(Observable) & 发送事件
    通过 Observable工厂方法创建被观察者对象(Observable)
    每次订阅后,都会得到一个刚创建的最新的Observable对象,这可以确保Observable对象里的数据是最新的
  • 8.5 timer
    快速创建1个被观察者对象(Observable)
    发送事件的特点:延迟指定时间后,发送1个数值0(Long类型)
    本质 = 延迟指定时间后,调用一次 onNext(0)
  • 8.6 interval
    快速创建1个被观察者对象(Observable)
    发送事件的特点:每隔指定时间 就发送 事件
// 参数说明:
        // 参数1 = 第1次延迟时间;
        // 参数2 = 间隔时间数字;
        // 参数3 = 时间单位;
        Observable.interval(3,1,TimeUnit.SECONDS)
                // 该例子发送的事件序列特点:延迟3s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
  • 8.7 intervalRange
    快速创建1个被观察者对象(Observable)
    发送事件的特点:每隔指定时间 就发送 事件,可指定发送的数据的数量
    a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
    b. 作用类似于interval(),但可指定发送的数据的数量
// 参数说明:
        // 参数1 = 事件序列起始点;
        // 参数2 = 事件数量;
        // 参数3 = 第1次事件延迟发送时间;
        // 参数4 = 间隔时间数字;
        // 参数5 = 时间单位
        Observable.intervalRange(3,10,2, 1, TimeUnit.SECONDS)
                // 该例子发送的事件序列特点:
                // 1. 从3开始,一共发送10个事件;
                // 2. 第1次延迟2s发送,之后每隔2秒产生1个数字(从0开始递增1,无限个)
  • 8.8 range
    快速创建1个被观察者对象(Observable)
    发送事件的特点:连续发送 1个事件序列,可指定范围
    a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
    b. 作用类似于intervalRange(),但区别在于:无延迟发送事件
  • 8.9 rangeLong
    作用:类似于range(),区别在于该方法支持数据类型 = Long
    具体使用与range()类似,此处不作过多描述
    在这里插入图片描述

9. subcribe与doOnNext,doOnError,doOnComplete区别

doOnNextdoOnErrordoOnComplete 是用于在数据流中插入副作用的操作符,而 subscribe() 是用于实际接收和处理事件的订阅方法。它们在功能和用途上有一些重要的区别:

1. 主要区别

  1. 目的和用途

    • subscribe():用于启动数据流并处理发射的每一个数据项、错误和完成事件。它是实际的订阅方法,定义了如何响应这些事件。
    • doOnNext():用于在每个数据项发射时插入副作用,例如日志记录或调试。它不会影响数据流的行为,也不会处理数据项。
    • doOnError():用于在发生错误时插入副作用,例如记录错误信息。它不会终止数据流,只是提供一个在错误发生时执行的钩子。
    • doOnComplete():用于在 Observable 完成时插入副作用,例如执行一些清理工作。它不会处理完成事件,只是提供一个在完成时执行的钩子。
  2. 触发情况

    • subscribe():触发时机是当你调用 subscribe() 方法时,数据流开始运行。
    • doOnNext():每当 Observable 发射新的数据项时触发。
    • doOnError():在 Observable 发射错误时触发。
    • doOnComplete():在 Observable 完成时触发。
  3. 返回值

    • 所有的 doOn* 方法返回的是一个新的 Observable,你可以继续对其进行链式操作。而 subscribe() 不返回任何值,它是一个终止操作。

2. 示例代码

下面是一个示例,展示了如何使用这些方法并说明它们的区别:

import io.reactivex.rxjava3.core.Observable;

public class Example {
    public static void main(String[] args) {
        Observable<String> observable = Observable.create(emitter -> {
            try {
                emitter.onNext("Hello");
                emitter.onNext("World");
                // 模拟一个错误
                if (true) {
                    throw new RuntimeException("发生错误!");
                }
                emitter.onComplete();
            } catch (Exception e) {
                emitter.onError(e);
            }
        });

        observable
            .doOnNext(item -> System.out.println("发射: " + item)) // 在发射每个项时触发
            .doOnError(throwable -> System.out.println("捕获到错误: " + throwable.getMessage())) // 发生错误时触发
            .doOnComplete(() -> System.out.println("完成时触发")) // 完成时触发
            .subscribe(
                item -> System.out.println("收到: " + item), // 处理成功发射的每个项
                throwable -> System.out.println("最终错误处理: " + throwable.getMessage()), // 最终处理错误
                () -> System.out.println("最终完成处理") // 处理完成
            );
    }
}

3. 总结

  • 使用 subscribe() 来处理实际的事件响应(成功项、错误和完成)。
  • 使用 doOnNext()doOnError()doOnComplete() 插入副作用逻辑,而不影响数据流的主逻辑。
  • 这些 doOn* 方法一般用于调试、日志记录或其他附加操作,而不会改变数据的流动或处理过程。

通过将这两种方法结合使用,可以实现清晰且高效的代码结构,既能处理数据流,也能监控副作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值