RxJava的学习(附demo)

什么是Rx

Rx是一个函数库,让开发者可以利用可观察序列和LINQ风格查询操作符来编写异步和基于事件的程序。简单来讲Rx就是一种响应式编程,来创建基于事件的异步程序

RxJava 到底是什么

RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"也就是官方定义:一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。

然而,对于初学者来说,这太难看懂了。因为它是一个『总结』,而初学者更需要一个『引言』。

其实, RxJava 的本质可以压缩为异步这一个词。说到根上,它就是一个实现异步操作的库,而别的定语都是基于这之上的。

RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。

观察者模式

  • 普通的观察者模式:

其中这个Button就是被观察者(Observable),OnClickListener就是观察者(Observer),两者通过setOnClickListener达成订阅(Subscribe)关系,之后当Button产生OnClick事件的时候,会直接发送给OnClickListener,它做出相应的响应处理。
  • RxJava的观察者模式呢,跟这个差不多,但是也有几点差别:
Observer与Observable是通过 subscribe() 来达成订阅关系。
RxJava中事件回调有三种:onNext() 、 onCompleted() 、 onError() 。
如果一个Observerble没有任何的Observer,那么这个Observable是不会发出任何事件的。

关于RxJava的回调事件:

  • onNext():基本事件。
  • onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
  • onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
值得注意的是在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。如果在队列中调用了其中一个,就不应该再调用另一个。

RxJava 好在哪

换句话说,『同样是做异步,为什么人们用它,而不用现成的 AsyncTask / Handler / XXX / ... ?』

异步操作很关键的一点是程序的简洁性,因为在调度过程比较复杂的情况下,异步代码经常会既难写也难被读懂。 Android 创造的 AsyncTask 和Handler ,其实都是为了让异步代码更加简洁。RxJava 的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。

如何实现RxJava

  • 创建Observer
这里我们new一个Observer出来,其实就是实现Observer的接口,注意String是接收参数的类型:
//1.创建观察者对象
        Observer<String> observer=new Observer<String>() {
            @Override
            public void onCompleted() {
                Log.e("kaka","onComlieted");
            }

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

            @Override
            public void onNext(String s) {
                Log.e("kaka","onNext");

            }
        };

当然这里也要提另外一个接口:Subscriber ,一个实现了 Observer 的抽象类:Subscriber。 Subscriber 对 Observer 接口进行了一些扩展,但他们的基本使用方式是完全一样的,实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。
  • 创建Observable
与Observer不同的是,Observable是通过 create() 方法来创建的。注意String是发送参数的类型:
//2.创建被观察者对象
        Observable<String> observable=Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("hi");
                subscriber.onNext("nihao");
                subscriber.onNext("kaka");
                subscriber.onCompleted();
            }
        });

  • 现在就需要用 subscribe() 方法来将它们连接起来,形成一种订阅关系:
        observable.subscribe(observer);

这里其实确实有点奇怪,为什么是Observable(被观察者)订阅了Observer(观察者)呢?其实我们想一想之前Button的点击事件:

Button.setOnClickListener(new View.OnClickListener())

Button是被观察者,OnClickListener是观察者,setOnClickListener是订阅。我们惊讶地发现,也是被观察者订阅了观察者,所以应该是一种流式API的设计吧,也没啥影响。
运行结果:

线程控制——Scheduler

在RxJava中,Scheduler相当于线程控制器,可以通过它来指定每一段代码运行的线程。

RxJava已经内置了几个Scheduler

Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的Scheduler。

Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。

Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的Scheduler。行为模式和newThread()差不多,区别在于io()的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()比newThread()更有效率。不要把计算工作放在io()中,可以避免创建不必要的线程。

Schedulers.computation(): 计算所使用的Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个Scheduler使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在computation()中,否则 I/O 操作的等待时间会浪费 CPU。

AndroidSchedulers.mainThread(),Android专用线程,指定操作在主线程运行。(需要导入RxAndroid依赖)

那我们如何切换线程呢?RxJava中提供了两个方法:subscribeOn() 和 observeOn() ,两者的不同点在于:

subscribeOn(): 指定subscribe()订阅所发生的线程,即 call() 执行的线程。或者叫做事件产生的线程。

observeOn(): 指定Observer所运行在的线程,即onNext()执行的线程。或者叫做事件消费的线程。

 Observable.just("hi","nihao","woshi")
                .subscribeOn(Schedulers.io())//被创建的事件内容"hi","nihao","woshi"将会在io线程发出
                .observeOn(AndroidSchedulers.mainThread())//字符串的打印将发生在主线程
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.e("kaka",s);
                    }
                });



一个基于RxJava的Demo

/**
     * 点击按钮,imageview显示图片
     *
     * @param view
     */

    public void downloadImg(View view) {
        Observable.create(new Observable.OnSubscribe<Bitmap>() {
            @Override
            public void call(Subscriber<? super Bitmap> subscriber) {
                subscriber.onNext(GetBitmapForUrl.getBitmap(url));//通过URL得到图片的bitmap对象
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Bitmap>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(Bitmap bitmap) {
                        imageView.setImageBitmap(bitmap);

                    }
                });
    }

运行结果:



几篇关于RxJava的文章:
Rx系列之RxJava操作符:http://www.jianshu.com/p/30e13d874a61
Rx系列之Rxjava操作符进阶-使用场景:http://www.jianshu.com/p/79cb4e1c9771

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章