Rxjava原理

12 阅读6分钟

参考文章

一 .基本用法

(1).Rxjava是一个用于处理异步和基于事件编程的Java库.

(2).Rxjava原理就是类似于观察者模式

  • 观察者模式面向的需求是:A 对象(观察者)对 B 对象(被观察者)的某种变化高度敏感,需要在 B 变化的一瞬间做出反应。举个例子,新闻里喜闻乐见的警察抓小偷,警察需要在小偷伸手作案的时候实施抓捕。在这个例子里,警察是观察者,小偷是被观察者,警察需要时刻盯着小偷的一举一动,才能保证不会漏过任何瞬间。

  • 程序的观察者模式和这种真正的『观察』略有不同,观察者不需要时刻盯着被观察者(例如 A 不需要每过 2ms 就检查一次 B 的状态),而是采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。

  • Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。

RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
//.create创建了一个Observable<String> 的可发射事件.
   Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e)  {
                e.onNext("1"); //可以多次调用
                e.onNext("1"); //可以多次调用
                e.onComplete();
              //  e.onError(new Exception());
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {     
            }
            @Override
            public void onNext(String s) {
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onComplete() {
            }
        });
在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。它们的区别对于使用者来说主要有两点。

A:onStart():这是 Subscriber 增加的方法。

B: unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅, 一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。

(3).操作符( map,floatmap,filter ,take ,takelast,distinct,skip变换操作符)

  • just操作符创建Observable被观察者对象
 Observable.just(1,2,3,4,5).subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.i(TAG,"onCompleted:");
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.i(TAG,"onNext:"+integer);//执行5次
                    }
                });
 
  • map操作符----将原Observable发射出来的数据转换为另外一种类型的数据
 
 
 Observable.just("666").map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) throws Exception {
                return Integer.parseInt(s);
            }
        }).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {

            } 

            @Override
            public void onNext(Integer integer) {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });


  • floatmap操作符---作用类似于map又比map强大,map是单纯的数据类型的转换,而flapMap可以将原数转换成新的Observables,再将这些Observables的数据顺序缓存到一个新的队列中,在统一发射出来
      List<AccountInfoBean> infoBeans=new ArrayList<>();
        infoBeans.add(new AccountInfoBean());
        infoBeans.add(new AccountInfoBean());
        infoBeans.add(new AccountInfoBean());
        Observable.just(infoBeans).flatMap(new Function<List<AccountInfoBean>, ObservableSource<AccountInfoBean>>() {
            @Override
            public ObservableSource<AccountInfoBean> apply(List<AccountInfoBean> beanList) throws Exception {
              //把beanList中的每个对象转换成Observable<AccountInfoBean>
                return Observable.fromIterable(beanList);
            }
        }).subscribe(new Consumer<AccountInfoBean>() {
            @Override
            public void accept(AccountInfoBean accountInfoBean) throws Exception {
                 System.out.println("xxx");//infoBeans中有3个元素,会执行3次
            }
        });

  • filter操作符----对发射的数据做一个限制,只有满足条件的数据才会被发射
//对发射的数据做一个限制,只有满足条件的数据才会被发射
                Observable.just("hello","Rxjava","Nice to meet you").filter(new Function<String, Boolean>() {
                    @Override
                    public Boolean apply(String s) {
                        return s.length()>5;
                    }
                }).subscribe(new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable throwable) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.i("TAG","filter过滤后的数据:"+s.toString());
                    }
                });
  • distinct操作符----过滤掉重复项
 Observable.just("hello","hello","hello","Rxjava","Rxjava","Nice to meet you").filter(new Function<String, Boolean>() {
                    @Override
                    public Boolean apply(String s) {
                        return s.length()>5;
                    }
                }).subscribe(new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable throwable) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.i("TAG","distinct去除重复之后的数据:"+s.toString());
                    }
                });
  • Skip操作符----发射数据时忽略前N项数据(skpiLast忽略后N项数据)
  Observable.just("hello","Rxjava","Nice to meet you").skip(2).subscribe(new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable throwable) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.i("TAG","Skip之后的数据:"+s.toString());
                    }
                });
  • take操作符----只发射前N项的数据(takeLast与take想反,只取最后N项数据)
 Observable.just("hello","Rxjava","Nice to meet you").take(2).subscribe(new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable throwable) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.i("TAG","Take之后的数据:"+s.toString());
                    }
                });

另外还有一些其他的操作符 range,Interval,empty,error等(www.jianshu.com/p/eceb6b31d…

二.线程调度Scheduler

(1).subscribeOn(Schedulers.io()) 或者observeOn(AndroidSchedulers.mainThread())

 Observable.just(1, 2, 3, 4)
                .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
                .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        
                    }

                    @Override
                    public void onNext(Integer integer) {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

(2). Rxjava通过flatMap操作符解决回调地狱问题(OkHttp会导致回调地狱,无法切换线程)

api.requestFirstData()
    .flatMap(data1 -> api.requestSecondData(data1.getId()))
    .flatMap(data2 -> api.requestThirdData(data2.getToken()))
    .subscribe(
        data3 -> {
            // 处理最终数据
        },
        throwable -> {
            // 处理错误,这里不管是哪个环节出错,都会走到这里
        }
    );

 //HttpResult<UserInfoBody>  =====>Observable<HttpResult<List<HotBean>>>
HttpRetrofit.apiService.getUserInfo().flatMap(object:Function<HttpResult<UserInfoBody>,Observable<HttpResult<List<HotBean>>>>{
        override fun apply(response: HttpResult<UserInfoBody>): Observable<HttpResult<List<HotBean>>>? {
           return   HttpRetrofit.apiService.getHotKeyListTest(response.data?.username?:"");
        }
    })

(3). kotlin协程,解决地狱回调问题。(第二接口依赖于第一个接口的参数)

// 注意:在真实开发过程中,MainScope作用域用的非常常用
MainScope().launch(){     // 注意:此协程块默认是在UI线程中启动协程
    // 下面的代码看起来会以同步的方式一行行执行(异步代码同步获取结果)
    val token = apiService.getToken()   // 网络请求:IO线程,获取用户token
    val user = apiService.getUser(token)// 网络请求:IO线程,获取用户信息
    nameTv.text = user.name             // 更新 UI:主线程,展示用户名
    val articleList = apiService.getArticleList(user.id)// 网络请求:IO线程,根据用户id获取用户的文章集合哦
    articleTv.text = "用户${user.name}的文章页数是:${articleList.size}页"   // 更新 UI:主线程
}

(4).zip操作符解决并发执行问题

Observable<Boolean> observable1 = Observable.create(new ObservableOnSubscribe<Boolean>() {
    @Override
    public void subscribe(ObservableEmitter<Boolean> emitter) throws Exception {
        // 模拟网络请求1
        Thread.sleep(1000);
        return "Data from API 1";
    }
}).subscribeOn(Schedulers.io());// 指定在IO线程执行请求

Observable<Boolean> observable2 = Observable.create(new ObservableOnSubscribe<Boolean>() {
    @Override
    public void subscribe(ObservableEmitter<Boolean> emitter) throws Exception {
        // 模拟网络请求2
        Thread.sleep(800);
        return "Data from API 2";
    }
}).subscribeOn(Schedulers.io());// 指定在IO线程执行请求


Observable.zip(observable1,observable2, (result1, result2) -> {
         //模拟收到result1和result2结果不为null
         CombineResult   combinedResult=new CombineResult(); 
         if(result1!=null&&result2!=null){
            combinedResult.result1=result1;
            combinedResult.result2=result2;
            return combinedResult;
         }
         return null;
 })
    .observeOn(AndroidSchedulers.mainThread()) // 在 UI 线程接收结果
    .subscribe(combinedResult -> {
        // 处理组合后的结果
        if(combinedResult!=null&&combinedResult.result1!=null&&combinedResult2!=null){
            //更新UI
        }
    });