RxJava—入门介绍

1.前言

       最近这段时间公司有一个项目需要重构,需要使用MVP+RxJava+Retrofit+RxBinding这样的模式进行,而最近一年多的时间来国内的技术圈子中也越来越多的开始提到RxJava,在进行项目重构之初经过一段时间的自学之后,我也深深的感受到了RxJava的魅力,RxJava使用的是响应式编程的思想,它能帮我们简化代码的逻辑(代替Android提供的AsyncTask和Handler等用来做异步操作的类库),提升代码的可读性,这对于后期的代码维护来说帮助是巨大的。

2.响应式编程

       在学习RxJava之前我们还需要了解到什么是响应式编程。响应式编程是一种基于异步数据流概念的编程模式,数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。事件是唯一的以合适的方式将我们的现实世界映射到我们的软件中:如果屋里太热了我们就打开一扇窗户。同样的,当我们的天气app从服务端获取到新的天气数据后,我们需要更新app上展示天气信息的UI;汽车上的车道偏移系统探测到车辆偏移了正常路线就会提醒驾驶者纠正,就是是响应事件。

3.什么是RxJava

       RxJava(RxJava的GitHub主页)在其GitHub主页上的自我介绍是"a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(翻译过来就是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库),这就是RxJava的本质性概括。用我自己的话来说,RxJava的本质上就是一个异步操作库,就是一个能让你用极其简洁的逻辑去处理繁琐复杂的异步任务事件。

       在我们进行异步操作的过程中最重要的一点就是简洁,通常在一个Android项目中避免不了调用接口,在调用成功之后对Activity中的UI进行更新,由于在调用接口是一个耗时的操作所以需要在子线程中进行,而更新UI的操作又必须在主线程中去操作,相信这一点大家都不陌生,在通常情况下我们都是使用的Android提供的AsyncTask和Handler等异步操作的类库,将子线程切换到主线程中。如果程序的逻辑比较简单这样写还是没有大的问题的,但是如果程序的逻辑比较复杂,在调用接口的过程中比较复杂,异步的代码经常会既难写又难被读懂,这时RxJava的优势就体现出来了,随着程序的逻辑变得越来越复杂,它依然能够保持简洁的特性。

4.RxJava的使用

       RxJava的异步实现时基于观察者模式来实现的,而且是一种扩展的观察者模式。在观察者模式中,观察者模式是基于Subject这个概念的,Subject是一种特殊的对象,又被称为被观察者者,当它改变时那些由它保存的一系列对象将会得到通知,而这一系列对象被称作Observer(观察者)。它们会对外暴漏了一个通知方法(比方说update之类的),当Subject状态发生变化时会调用的这个方法。如果你现在对观察者模式不是很了解,那么强烈建议你去先了解下观察者模式再往下继续学习。

       在RxJava的扩展的观察模式中,主要有4个概念:observable(被观察者)、observer(观察者)、事件和subscribe(订阅)。observable(被观察者)和observer(观察者)是通过subscribe(订阅)方法来实现订阅关系的,从而observable(被观察者)在需要的时候可以发出事件来通知observer(观察者)。

       Android 开发中一个比较典型的例子是点击Button触发监听器OnClickListener,对设置OnClickListener来说Button是被观察者,OnClickListener是观察者,二者通过setOnClickListener()方法达成订阅关系。订阅之后当用户点击Button的瞬间,AndroidFramework就会将点击事件发送给已经注册的OnClickListener(观察者),采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。当然,这也得益于我们可以随意定制自己程序中的观察者和被观察者。

       OnClickListener的模式大致如下图:


       与传统的观察者模式相比较来说,RxJava的事件回调方法除了普通事件onNext()(相当于onClick()/onEvent())之外,还定义了两个特殊的事件:onCompleted()和onError()。

       onCompleted(): 事件队列完结。RxJava不仅把每个事件单独处理,还会把它们看做一个队列。RxJava中规定当不会再有新的onNext()发出时,需要触发onCompleted()方法作为标志。

       onError(): 事件队列异常。在事件处理过程中出异常时,onError()会被触发的同时队列也会自动终止,不允许再有事件发出。

       在一个正确运行的事件序列中, onCompleted()和onError()有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted()和onError()二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

       RxJava 的观察者模式大致如下图:


基于以上的概念,RxJava的基本实现主要有一下三点:

(1)创建Observer

       在使用RxJava的框架之前,在Android Studio中还需要引入依赖,需要在build.gradle中加入

       compile 'io.reactivex:rxjava:1.0.14'

       compile 'io.reactivex:rxandroid:1.0.1'

       如以下部分代码所示:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.1'
    compile 'io.reactivex:rxjava:1.0.14'
    compile 'io.reactivex:rxandroid:1.0.1'
    testCompile 'junit:junit:4.12'
}

       Observer即观察者,它决定了事件触发的时候该有怎样的行为。RxJava 中的 Observer 接口的实现方式:

Observer<String> observer = new Observer<String>()
{
	public void onNext(String s)
	{
		Log.d(tag, "Item: " + s); 
	} 
	public void onCompleted() 
	{
		Log.d(tag, "Completed!"); 
	}
	public void onError(Throwable e) 
	{ 
		Log.d(tag, "Error!"); 
	}
};

       除了Observer接口之外,RxJava还内置了一个实现了Observer的抽象类:Subscriber。Subscriber对Observer接口进行了一些扩展,但他们的基本使用方式是完全一样的:

Subscriber<String> subscriber = new Subscriber<String>() 
{ 
	public void onNext(String s) 
	{ 
		Log.d(tag, "Item: " + s); 
	} 
	public void onCompleted() 
	{ 
		Log.d(tag, "Completed!"); 
	}
	public void onError(Throwable e) 
	{ 
		Log.d(tag, "Error!"); 
	}
};
       以上两者的在创建Observer不仅使用方式是一样的,实际上在RxJava的订阅过程中,Observer也总是先被装换成为一个Subscriber再使用的,所以如果你只想使用基本功能,选择Observer和Subscriber是完全一样的。它的区别对于使用者来说主要有两点:

  1. onStart(): 这是Subscriber增加的方法。它会在subscribe刚开始事件还未发送之前被调用,可以用于做一些准备工作,例如数据的初始化。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行),onStart()就不适用了,因为它总是在subscribe所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用doOnSubscribe()方法。
  2. unsubscribe(): 这是Subscriber所实现的另一个接口Subscription的方法,用于取消订阅。在这个方法被调用后,Subscriber将不再接收事件。一般在这个方法调用前,可以使用isUnsubscribed()先判断一下状态。unsubscribe()这个方法很重要,因为在subscribe()之后,Observable会持有Subscriber的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中调用unsubscribe()来解除引用关系,以避免内存泄露的发生。

(2)创建Observable

       Observable即被观察者,它决定什么时候触发以及触发什么样的事件,RxJava中使用create()方法来创建一个Observable的对象,并且定义事件触发的规则。

Observable observable = Observable.create(new Observable.OnSubscribe<String>() 
{
    public void call(Subscriber<? super String> subscriber) 
    {
        subscriber.onNext("Hello");
        subscriber.onNext("Android");
        subscriber.onNext("IOS");
        subscriber.onCompleted();
    }
});
       从上面的代码中可以看到, create()方法中传入了一个OnSubscribe对象做为参数,OnSubscribe对象会被储存在返回的Observable的对象中,OnSubscribe对象的作用就相当于一个计划表,当Observable的对象被订阅的时候就会自动触发其中的call()方法,就是观察者Subscriber将会调用三次onNext()方法和一次onCompleted()方法,这样被观察者就调用了观察者中的回调方法,就实现了由被观察者向观察者的事件传递,即实现了观察者模式。

       除了使用create()方法创建Observable的事件序列,基于这个方法RxJava还提供了其它的方法创建Observable的事件序列。

使用just():将传入的参数依次发送出来

Observable observable = Observable.just("Hello", "Android", "IOS");
       以上的observable被订阅的时候会依次调用onNext("Hello")、onNext("Android")、onNext("IOS")和onCompleted()。

使用from(Iterable<? extends T>):将传入的数组或者Iterable拆分成具体对象后,依次发送出来

String[] words = {"Hello", "Android", "IOS"};
Observable observable = Observable.from(words);
        同理,以上的observable被订阅的时候也会依次调用onNext("Hello")、onNext("Android")、onNext("IOS")和onCompleted()。

(3)Subscribe(订阅)

       在成功的创建了Observable(被观察者)和Observer(观察者)之后,再使用Subscribe(订阅)将二者关联起来,就可以工作了。

observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);
       除了subscribe(Observer)和subscribe(Subscriber),subscribe()还支持不完整意义上的回调,RxJava会自动根据定义创建出Subscriber。
Action1<String> onNextAction = new Action1<String>() 
{
    // onNext()
    public void call(String s) 
    {
        Log.d(tag, s);
    }
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() 
{
    // onError()
    public void call(Throwable throwable) 
    {
        // Error handling
    }
};
Action0 onCompletedAction = new Action0() 
{
    // onCompleted()
    public void call() 
    {
        Log.d(tag, "completed");
    }
};

// 自动创建Subscriber,并使用onNextAction来定义onNext()
observable.subscribe(onNextAction);
// 自动创建Subscriber,并使用onNextAction和onErrorAction来定义onNext()和onError()
observable.subscribe(onNextAction, onErrorAction);
// 自动创建Subscriber,并使用onNextAction、onErrorAction和onCompletedAction来定义onNext、onError()和onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
       在上面的代码中出现了Action0和Action1这样的接口,其实这两个接口都是属于RxJava中的,Action0和Action1相比较而言,Action0中只有一个call()方法,并且这个方法是无参数无返回值的,而Action1中同样也只有一个call()方法,相同的是这个call()方法也是无返回值的,不同的是这个方法有一个参数。根据这两个接口的特性而言,由于 onCompleted()方法也 是无参无返回值的,因此Action0可以被当成一个包装对象,将onCompleted()的内容打包起来将自己作为一个参数传入subscribe()以实现不完整定义的回调,这样其实也可以看做将onCompleted()方法作为参数传进了 subscribe()。而onNext(T obj)和onError(Throwable e)也是单参数无返回值的,因此Action1可以将 onNext(obj)和onError(error)打包起来传入subscribe()以实现不完整定义的回调。事实上,RxJava不仅仅为我们提供了Action0和Action1这样的接口,还提供了多个ActionX形式的接口,它们可以用来包装无返回值有一个或者多个参数的方法。

5.线程控制

       在RxJava的默认规则中,事件的发出和消费都是在同一个线程中的,也就是说,使用上面的方法实现出来的只是一个同步的观察者模式,我们使用观察者模式的目的就是,实现后台处理,前台回调的异步机制,因此异步对于RxJava来说是至关重要的,好在RxJava中为我们提供了Scheduler来指定事件发生所在的线程。

       在RxJava中,Scheduler就相当于线程控制器,RxJava通过使用Scheduler来指定每一段代码应该运行在什么线程中,在RxJava中已经为我们内置了几个Scheduler,这些Scheduler能够满足我们绝大多数的使用场景。


       有了这几个Scheduler,我们就可以使用RxJava还为我们提供了subscribeOn()和observeOn()两个方法来指定Observable和Observer运行的线程。subscribeOn()指定了subscribe()所发生的线程,即Observable.OnSubscribe被激活时所处的线程,或者叫做事件产生的线程。observeOn()指定Subscriber所运行在的线程,或者叫做事件消费的线程。

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() 
    {
        public void call(Integer number) 
        {
            Log.d(tag, "number:" + number);
        }
    });
       在上面的代码中,由于开始有subscribeOn(Schedulers.io())的指定,被创建被观察者将会在IO线程中执行,而由于observeOn(AndroidScheculers.mainThread())的指定,因此观察者(subscriber)数字的打印将发生在主线程中,实际在项目中使用RxJava,这种在subscribe()之前写上两句subscribeOn(Scheduler.io())和 observeOn(AndroidSchedulers.mainThread())的使用方式非常常见,它适用于多数的子线程获取数据,主线程显示数据的程序策略。










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值