RxJava2.x初识

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wang_yong_hui_1234/article/details/73250039

一,初识RxJava

(1),什么是RxJava?

RxJava是 ReactiveX(ReactiveX推荐http://reactivex.io/) 在JVM上的一个实现,ReactiveX使用Observable序列组合异步和基于事件的程序。RxJava是在ReactiveX的一个延伸,RxJava是轻量级的,RxJava只关注Observable的抽象和与之相关的高级函数。通俗一点,RxJava是一个编程模型,提供一致的编程接口,帮助我们处理异步数据流。RxJava是以函数的响应方式体现。

(2),为什么要使用RxJava?

从表面来讲,RxJava编写代码简洁,注意简洁不是简单。代码量并不一定能减少,只是结构清晰,便于阅读。其实最根本的是,RxJava可以灵活的处理数据流或事件,高效的处理线程创建和并发。

二,如何使用RxJava

(1),如果使用AndroidStudio,需要在gradle中添加

    //RxJava的依赖包
    compile 'io.reactivex.rxjava2:rxjava:2.0.1'
    //RxAndroid的依赖包
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

(2),这里以RxJava2.x版本介绍如何使用,建议读者可以先看下RxJava1.x版本,这样可以对比版本差异,有助于更好的理解RxJava。
(3),使用场景,通常在Android开发过程中,需要在后台线程处理一些任务。比如:AsyncTask,ContentProvider,Services,网络请求等。使用AsyncTask会导致内存泄漏,ContentProvider和Services配置繁琐。而RxJava就可以帮助我们解决这些问题。

三,RxJava观察者模式

(1),概念:Android开发中,我们经常用到的点击事件就是观察者模式。View就是被观察者,OnClickListener 是观察者,两者通过setOnClickListener建立绑定关系(这里简单介绍,如果想了解Android更多开发模式,推荐书籍《Android源码设计模式》)

(2),Observable(被观察者)/Flowable(被观察者 RxJava2.x版本新增),Observer(观察者)/Subscriber(观察者),Subscribe(订阅者)。观察者和被观察者通过订阅建立绑定关系。

(3),RxJava2.X中, Observeable用于订阅Observer ,是不支持背压的,而 Flowable用于订阅Subscriber ,是支持背压(Backpressure)的。背压是指:被观察者发送数据或事件的速度,远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略。关于背压的概念推荐http://blog.csdn.net/jdsjlzx/article/details/52717636

四,操作符

(1),create()
使用 Create操作符从头开始创建一个Observable/Flowable,这个操作符传递一个接受观察者作为参数的函数。

   //创建被观察者
   Observable observable = Observable.create(new ObservableOnSubscribe<String>() {

            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("Hello Word");
                e.onComplete();
            }
        });
   //创建观察者     
   Observer observer = new Observer<String>() {
            //这是RxJava2.x新加入的方法,在订阅之后发送数据之前,而Disposable可用于取消订阅
            @Override
            public void onSubscribe(Disposable d) {
                Log.e(TAG, "onSubscribe");

            }

            @Override
            public void onNext(String s) {
                Log.e(TAG, s);
            }

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

            @Override
            public void onComplete() {
                Log.e(TAG, "onComplete");
            }
        };
    //建立绑定关系   
    observable.subscribe(observer);

以上代码为Observable 实现方式 , 打印结果为 onSubscribe->Hello Word->onComplete。在这里就可以看出,onSubscribe会在onNext之前调用,这里可以在onSubscribe方法中做一些初始化的操作。

扫描二维码关注公众号,回复: 4599853 查看本文章
     Flowable flowable = Flowable.create(new FlowableOnSubscribe(){

            @Override
            public void subscribe(FlowableEmitter e) throws Exception {
                e.onNext("Hello Word");
                e.onComplete();
            }
        }, BackpressureStrategy.BUFFER);//背压模式,不指定不支持背压
     Subscriber subscriber = new Subscriber<String>() {

            @Override
            public void onSubscribe(Subscription s) {
                Log.e(TAG, "onSubscribe");
                s.request(1);//request(n)来告诉上游被观察者发送多少个数据
            }

            @Override
            public void onNext(String s) {
                Log.e(TAG, s);
            }

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

            @Override
            public void onComplete() {
                Log.e(TAG, "onComplete");
            }
        };
    flowable.subscribe(subscriber);
  • 以上代码为Flowable 实现方式打印结果为onSubscribe->HelloWord->onComplete。这里需要注意,如果有初始化操作要在request(n)之前执行。Flowable是支持背压的,简单来说,上游被观察者会响应下游观察者的数据请求,下游观察者通过request(n)通知上游被观察者发送多少请求。这样避免被观察者发送数据或事件的速度,远快于观察者处理数据或事件的速度,造成大量数据或事件堆积。

  • 被观察者ObservableEmitter/FlowableEmitter,这里指发射器的意思,可以发射onNext(),onError(),onComplete()。被观察者可以发送多个onNext(),观察者也可以接收多个onNext()。被观察者发送了onComplete()/onError()之后事件继续发送,而观察者接收到onComplete()之后不在继续接收事件。被观察者可以不发送onComplete()/onError(),两者必须是唯一并且互斥。

  • 观察者Disposable ,这里指丢弃的意思,调用它观察者收不到事件,而对被观察者没有影响

(2),just()
将一个或多个对象转换成发射这个或这些对象的一个Observable/Flowable

    Observable.just("Hello World", "Very Good").subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e(TAG, s);
            }
        });
    Flowable.just("Hello World", "Very Good")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        Log.e(TAG, s);
                    }
                });

这里有个Consumer,表示观察者只关心onNext()事件,其他事件不管,因此可以这么写
(3),range()
创建一个发射指定范围的整数序列的Observable/Flowable,可以指定范围的起始和长度。接受两个参数,一个是范围的起始值,一个是范围的数据的数目。

     Observable.range(3, 4).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG, integer + "");
            }
        });
        //输出3,4,5,6
     Flowable.range(2,4).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG, integer + "");
            }
        });
        //输出2,3,4,5

(4),flatMap()
将一个发射数据的Observable变换为多个Observables,然后将它们发射的数据合并后放进一个单独的Observable。
如何使用flatMap(),例如:我们需要做一个商品分类,主商品(Goods)和子商品(Category)。

 new Thread(new Runnable() {
            @Override
            public void run() {
                //在子线程获取数据
                List<Goods> list=//数据源,所有商品,比如:鞋子类别中包含运动鞋,登山鞋,板鞋等
                for(//主商品,如:鞋子){
                    Log.e(TAG,"主商品名称");
                    for(//子商品,如:运动鞋){
                            //主线程中更新UI
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Log.e(TAG,"子商品");
                                }
                            });
                    }
                }
            }
        }).start();

这段伪代码是我们常用的写法,在子线程中获取数据,主线程中更新UI,如果数据比较多,逻辑复杂代码可读性当然会差。再看看flatMap()应该怎么写

 Flowable.fromIterable(goods).flatMap(new Function<Goods, Publisher<Category>>() {
            @Override
            public Publisher<Category> apply(Goods goods) throws Exception {
                return Flowable.fromIterable(goods.getList());
            }

        })
                .subscribeOn(Schedulers.io())//下边会介绍
                .observeOn(AndroidSchedulers.mainThread())//下边会介绍
                .subscribe(new Consumer<Category>() {
                    @Override
                    public void accept(Category category) throws Exception {
                        Log.e(TAG, category.getName());
                    }
                });

对比一下这种方式结构清晰了很多,和flatMap()一样的还有一个操作符contactMap(),唯一的区别就是flatMap()是无序的,最后输出的和原序列不一定相同。contactMap()是有序的,最后输出的和原序列相同

有关操作符就介绍到这里,如果想了解其他操作符可以进入http://reactivex.io/进行查看

五,线程控制(Scheduler)

(1),对于Android开发来说,这也是最有用的地方。我们经常需要在程序中做一些耗时的操作,比如:网络请求,文件操作,数据库操作。通常我们都是在子线程中做一些耗时操作,在主线程中更新ui。
(2),Scheduler都有哪些有用的方法呢

  • Schedulers.newThread()
    总是启用新线程,并在新线程执行操作
  • Schedulers.io()
    代表io操作的线程, 通常用于网络,读写文件等io密集型的操作。和newThread()差不多,不过Schedulers.io()这里内部用到了线程池,比newThread()效率更高
  • Schedulers.computation()
    代表CPU计算密集型的操作, 例如需要大量计算的操作
  • AndroidSchedulers.mainThread()
    代表Android的主线程

(3),当我们创建一个Observable/Flowable默认是在主线程中进行,如下代码:

 Flowable.just("Hello World", "Very Good")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        Log.e(TAG, Thread.currentThread().getName());
                    }
                });
        //打印结果 main

如上代码,不管是观察者还是被观察者,如果不指定Scheduler,它就是默认的线程。开发过程中往往我们需要指定线程,如何进行变换呢?

 Flowable<Integer> flowable = Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> e) throws Exception {
                Log.e(TAG, "subscribe   " + Thread.currentThread().getName());
                e.onNext(1);
            }
        }, BackpressureStrategy.BUFFER);
        Consumer<Integer> consumer = new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG, "accept   " + Thread.currentThread().getName());
            }
        };
        flowable.subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(consumer);
                //打印结果  subscribe   RxNewThreadScheduler-1 
                           accept   main

可以看出,被观察者在子线程中进行,观察者在主线程中进行,主要是因为

subscribeOn(Schedulers.newThread())
observeOn(AndroidSchedulers.mainThread())

subscribeOn()指定上游被观察者的线程,observeOn()指定下游观察者的线程

有关RxJava2.x就简单介绍到这里,如果有时间会做一个项目,系统的使用这个框架。本文并非完全原创,参考了一些文章加上自己的理解,简化了一些内容,没有涉及源码,对于初学者来说容易上手

猜你喜欢

转载自blog.csdn.net/wang_yong_hui_1234/article/details/73250039