RxJava 1.x

关键词:
Observable 被观察者Observer 观察者Subscribe 订阅方法
Subscriber Observer的实现类Action 替代Subscriber

RxJava 是什么:异步

RxJava在Github 主页上的介绍是:

"a library for composing asynchronous and event-based programs using observable sequences for the Java VM"
翻译过来是:
一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库

RxJava 的好处是什么:简洁

Android创造的 AsyncTaskHandler ,其实都是为了让异步代码更加简洁。RxJava的优势也是简洁,但是其不同的是,随着程序逻辑变得越来越复杂,它依然保持简洁(逻辑简洁)

例子:

假设有这么一个需求,界面有一个自定义的视图imageCollectorView ,它的作用是显示多张图片,并能使用 addImage(Bitmap) 方法来任意增加显示的图片。现在需要程序将一个给出的目录数组 File[] floders 中每个目录下的png图片都加载出来并显示在自定义视图中。需要注意的是:由于读取图片的这一过程较为耗时,需要放在后台执行,而图片的显示则必须在UI线程执行。
常用的实现方法有多种,我们这里贴出其中一种:

普通方法实现
new Thread(){
	@Override
	public void run(){
		for(File folder: floders){	
			File[] files = folder.listFile();
			for(File file: files){
				if(file.getName().endsWith(".png")){
					final Bitmap bitmap = getBitmapFromFile(file);
					getActivity().runOnUiThread(new Runnable(){
						@Override
						public void run(){
							imageCollectorView.addImage(bitmap);
						}
					});
				}
			}
		}
	}
}.start();

而如果使用RxJava,实现方式是这样的:

RxJava实现
Observable.from(folders)  //将目录数组传入
	.flatMap(new Funcl<File,Observable<File>>(){
		@Override
		public Observable<File> call(File file){	
			return Observable.from(file.listFiles());
		}
	})
	.fileter(new Funcl<File,Boolean>(){
		@Override
		public Boolean call(File file){\
			return file.getName().endsWith(".png");
		}	
	})
	.map(new Funcl<File,Bitmap>(){
		@Override
		public Bitmap call(File file){
			return getBitmapFromFile(file);
		}
	})
	.subscribeOn(Schedulers.io())
	.observeOn(AndroidSchedulers.mainThread())
	.subscribe(new Action<Bitmap>(){
		@Override
		public void call(Bitmap bitmap){
			imageCollectorView.addImage(bitmap);
		}
	});

API介绍和原理解析

概念:扩展的观察者模式

RxJava 的异步实现,是通过一种扩展的观察者模式来实现的
观察者模式面向的需求是:

  • A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B变化的一瞬间做出反应。
    例如:警察抓小偷,警察是观察者,需要时刻盯着小偷的一举一动,并在需要小偷伸手作案的时候实施抓捕。
    程序的观察者模式与真正的观察略有不同,观察者不需要时刻盯着被观察者,而是采用**注册(Register)或者成为订阅(Susscribe)**的方式,告诉被观察者,我们需要你的某某状态,你要在它变化的时候通知我。

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

而RxJava作为一个工具库,使用的是通用形式的观察者模式。

RxJava的观察者模式

RxJava有四个基本概念:

  • Observable(可观察者,即被观察者)
  • Observer(观察者)
  • subscribe(订阅)
  • 事件

ObservableObserver 通过subscribe方法实现订阅关系,从而Observable 可以在需要的时候发出事件来通过 Observer

与传统的观察者模式不同,RxJava的事件回调方法除了普通事件onNext() (相当于 onClick / onEvent() )之外,还定义了两个特殊的事件:onCompletedonError()

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

RxJava的观察者模式大致如下图:
在这里插入图片描述

基本实现

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

1)创建Observer
Obserber 即 观察者,它决定事件触发的时候将有怎样的动作。RxJava中的 Observer 接口的实现方式:

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

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

Subscriber<String> subscriber = new Subscriber<String>(){
	@Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

不仅基本使用方式一样,实质上,在RxJava的subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 ObserverSubscriber 是完全一样的。它们的区别对于使用者来说主要有两点:

  • onStart():这是 Subscriber 增加的方法,它会在subscribe(订阅过程),而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清空或者重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是:如果对准备工作的线程有要求(例如弹出一个进度条,必须执行在主线程),onStart 就不适合用了,因为它总是在subscribe 所发生的线程被调用,而不能指定线程。要在指定线程来做准备工作,可以使用 doOnSubscribe() 方法
  • 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>(){
	@Override
	public void call(Subscriber<? super String> subscriber){
		subscriber.onNext("Hello");  //onNext 相当于 onClick,onEvent 等
		subscriber.onNext("Hi");
		subscriber.onNext("Aloha");
		subscriber.onCompleted();
	}
}

可以看到,这里传入了一个 OnSubscribe 对象作为参数。 OnSubscribe 会被储存在返回的 Observale 对象中,它的作用相当于一个计划表,当 Observable 被订阅的时候, Onsubscribecall() 方法会自动被调用,事件序列就会依照设定依次触发(对于上面的代码,就是观察者 Subscriber 将会被调用三次 onNext() 和 一次 onCompleted() )。这样,由被观察者调用了观察者的回调方法,就实现了由被观察者向观察者的事件传递,即 观察者模式

create() 方法是 RxJava最基本的创建事件序列的方法。基于这个方法,RxJava还提供了一些方法用来快捷创建事件队列 ,例如:

  • just(T…) :将传入的参数一次发送出来
    Observable observable = Observable.just("Hello", "Hi","Aloha");
    //将会一次执行
    //onNext("Hello");
    //onNext("Hi");
    //onNext("Aloha");
    //onCompleted();
    
  • from(T[]) / from(Iterable<? extends T>):将传入的数组或Iterable 拆分成具体对象后,一次发送出来
    String[] words = {"Hello","Hi","Aloha"};
    Observable observable = Observable.from(words);
    	//将会一次执行
    	//onNext("Hello");
    	//onNext("Hi");
    	//onNext("Aloha");
    	//onCompleted();
    

上面 just(T…) 的例子和 from(T[]) 的例子,都和之前 *create(OnSubscribe)的例子是等价的。

3)Subscribe(订阅)
创建了 ObservableObservaber 之后,再用 *subscribe()*方法将它们联结起来,整条链子就可以工作了。代码形式很简单:

observable.subscribe(observer);
//或者:
observable.subscribe(subscriber);

其中,Observable.subscribe(Subscriber)的内部实现是这样的(仅核心代码):

//注意,这不是 subscribe 的源码,而是将源码中与 性能、兼容性、扩展性有关的代码剔除后的核心代码
//如果需要看源码,可以去 RxJava 的 Github 仓库下载
public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

可以看到, subscrite() 做了三件事:

  • 调用Subscriber.onStart() ,这个方法在前面已经介绍了,是一个可选的准备方法
  • 调用Observable中的OnSubscribe.call(Subscriber)
    。在这里,事件发送的逻辑开始运行,从这可以看到,在RxJava中,Observable
    并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当*subscribe()*方法执行的时候。
  • 将传入的Subscriber 作为 Subscription 返回,这是为了方便 unsubscribe()

整个过程中对象之间的关系:
在这里插入图片描述

场景示例

打印字符串数组
将字符串数组 names 中的所有字符串依次打印出来:

String names  = ...;
Observable.from(names)
	.subscribe(new Subscriber<String>(){
		@Override
		public void onNext(String){
			Log.i("mylog",String);
		}
		@Override
		public void onCompleted(){
		}
		@Override
		public void onError(Throwable e){
		}
	});

但是我们只需要用到 onNext方法,还有两个重写的onErroronCompleted 并没有用,这样导致我们多出了几行根本不用的代码。于是可以用 Action 代替Subscriber得到的代码是:

String[] names = ..;
Observable.from(names)  //返回被观察者
	.subscribe(new Action1<String>(){
		@Override
		public void call(String name){
			Log.d(tag, name);
		}
	});

什么是Action
Acton 是 RxJava的一个接口,常用的有Action0Action1

  • Action0:它只有一个Call 方法,这个方法是无参无返回值的;由于onCompleted 方法也是无参无返回值的,因此Action0 可以被当成一个包装对象
  • Action1:它同样只有一个 call(T param) 方法,这个方法也没有返回值,但有一个参数,与Action0同理,由于 onNext(T obj)onError(Throwable error) 也是单参数无返回值,因此Action1可以将onNext和 onError打包起来传入subscribe() 以实现不完整定义的回调

Action的使用
定义三个对象,分别打包onNext(obj)、onError(error)、onCompleted()

Observable observable = Observable.just("Hello", "World");
        //处理onNext()中的内容
        Action1<String> onNextAction = new Action1<String>() {
            @Override
            public void call(String s) {
                Log.i(TAG, s);
            }
        };
        //处理onError()中的内容
        Action1<Throwable> onErrorAction = new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {

            }
        };
        //处理onCompleted()中的内容
        Action0 onCompletedAction = new Action0() {
            @Override
            public void call() {
                Log.i(TAG, "Completed");

            }
        };

接下来使用subscribe重载的方法

//使用 onNextAction 来定义 onNext
Observable.just(“Hello”,"World").subscribe(onNextAction);
//使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
Observable.just("Hello", "World").subscribe(onNextAction, onErrorAction);
//使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()
Observable.just("Hello", "World").subscribe(onNextAction, onErrorAction, onCompletedAction);

那为什么使用Action也能达到使用Subscriber的结果?源码如下:
在这里插入图片描述

原理很简单,就是通过传入的Action的参数数量来决定其内部Subscriber执行的方法,其根本还是在执行Subscriber的三个方法。

由id取得图片并显示
有指定的drawable 文件id drawableRes 取得图片,并显示在 ImageView中,并在出现异常的时候打印Toast报错:

int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>(){
	@Override
	public void call(Subscriber<? super Drawable> subscriber){
		Drawable drawable = getTheme().getDrawable(drawableRes));
		subscriber.onNext(drawable);
		subscriber.onCompleted();
	}
}).subscribe(new Observer<Drawable>(){
	@Override
	public void onNext(Drawable drawable){
	}
	@Override
	public void onCompleted(){
	}
	@Override
	public void onErro(Throwable e){
	}
});

正如上面两个例子,创建出 ObservableObserver ,在用 subscribe() 将它们串起来,一次RxJava 的基本使用就完成了

然而,在RxJava的默认规则中,事件的发出和消费都是在同一个线程的,也就是说,如果只用上面的方法,实现出来的只是一个同步的观察者模式。观察者模式本身的目的就是为了完成异步机制,因此异步对于RxJava来说非常重要,而要实现异步,则需要用到RxJava的另一个概念:Scheduler

Scheduler(调度器)—线程控制

Scheduler的API

在RxJava中,Scheduler -------调度器,相当于线程控制器,RxJava通过它来指定每一段代码应该运行在什么样的线程。RxJava已经内置了几个Scheduler ,它们已经适合大多数的使用场景:

  • Schedulers.immediate():直接在当前线程运行,相当于不指定线程,这是默认的Shceduler
  • Schedulers.newThread() :总是启用新线程,并在新线程执行操作
  • Schedulers.io():I/0操作(读写文件,读写数据库,网络信息交互等)所使用的Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是用一个无数量上限的线程池,可以重用空闲的线程,因此大多数情况下io()newThread 更有效率,不要把计算机工作放在 io() 中,可以避免创建不必要的线程
  • Schedulers.computation() :计算所使用的Scheduler ,这个计算是指CPU密集型计算,即不会被I/O等操作限制性能的操作,例如图形的计算。这个Scheduler 使用的固定的线程池,大小为CPU核数。不要把I/O 操作放在 computation 中,否则I/O操作等等待时间会浪费CPU
  • 另外,Android 还有一个专用的AndroidSchedulers.mainThread() ,它指定的操作将在Android主线程运行

有了这几个Scheduler ,就可以使用subscribeOn()observeOn() 两个方法来对线程进行控制了。
subscribeOn() :指定subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。
observeOn():指定Subscriber 所运行的线程,或者叫事件消费的线程。

示例代码

Observable.just(1,2,3,4)
	.subscribeOn(Schedulers.io) //指定订阅发生在IO线程
	.observeOn(AndroidSchedulers.mainThread()) //指定Subscriber 的回调发生在主线程
	.subscrite(new Action1<Integer>(){
		@Override
		public void call(Integer number){
			Log.d(tag, "number:"+number);
		}
	});

上段代码中,被创建的事件的内容将会在IO线程发出,而数据的回调将在主线程中,这种适用于多少的【后台线程取数据,主线程显示】

Scheduler 原理

变换

API
变换的原理:lift()
compose:对 Observable 整体的变换

RxJava 适合场景和使用方式

参考:https://gank.io/post/560e15be2dca930e00da1083#toc_1
参考:https://gank.io/post/560e15be2dca930e00da1083

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值