一、RxJava的简单介绍
在GitHub里面,RxJava的官方定义是:
"a library for composing asynchronous and event-based programs using observable sequences for the Java VM"
这里大概翻译是:
一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。
笔者这里总结本质定义RxJava这个库就是以异步作为基准的应用库。
二、RxJava的优势
无论如何,
RxJava最大的在于“简洁、异步!”在Android中,比较常用的异步方式有AsyncTasK或者Handler,但是
RxJava相对于其他的异步处理方式中,会显示得更加简洁。我们做过开发也知道,如果在一个异步处理的方法中,如果逻辑比较复杂,相信代码会变得越来越复杂,更加难被读懂。
但是,
RxJava最大优势能够依然保持简洁。
这里举个例子:
首先场景:在阅读软件中,需求是需要在遍历内存卡下面存在的文档,并且显示更新在界面中。
1.这是比较常见的实现方法(Thread 负责后台逻辑 + handler负责更新UI)
final String filePath = Environment.getExternalStorageDirectory().getPath();//获取跟目录
new Thread() {
@Override
public void run() {
super.run();
File files = new File(filePath);
File file[] = files.listFiles();
for (int i = 0; i < file.length; i++) {
if (file[i].getName().endsWith(".txt")){
paths.add(file[i].getPath());
}
}
handler . sendEmptyMessage ( 0 ); //handler 更新UI}
}.start();
2.使用
RxJava实现方式
final String filePath = Environment.getExternalStorageDirectory().getPath();//获取跟目录
File files = new File(filePath);
File file[] = files.listFiles();
Observable.from(file)
.map(new Func1<File, String>() {
@Override
public String call(File file) {
if (file.getName().endsWith(".txt"))
return file.getPath();
return "";
}
})
.subscribeOn(Schedulers.io())//指定subscribe在io线程
.observeOn(AndroidSchedulers.mainThread())//回调是主线程
.subscribe(new Action1<String>() {
@Override
public void call(String path) {
bookView.addFile(path);//自定义书架View,添加文件路径
}
});
如果读者懂得lambda方式的写法,RxJava还可以变化为如下:
Observable.from(file)
.map(path -> file.getPath)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(path -> bookView.addFile(path));
够清晰吧!
估计在看过这两个对比之后,会说
RxJava并没什么卵用 = =,这里笔者只是举个简单的例子更好说明了
RxJava中发布者与订阅者的两者关系。如果读者还想深入,
RxJava提供的API文档还是相当多的操作符,功能还是更加强大的,这里给个传送门:文档传送门
说起f发布者(
Observable
)与订阅中(
subscribe
)
两者之间的关系,相信用过EventBus的读者,对于这个概念是比较熟悉的。
RxJava 有四个基本概念:Observable
(可观察者,即被观察者)、 Observer
(观察者)、 subscribe
(订阅)、事件。Observable
和 Observer
通过 subscribe()
方法实现订阅关系,从而 Observable
可以在需要的时候发出事件来通知 Observer
。
RxJava与传统观察者模式不同, RxJava 的事件回调方法除了普通事件 onNext()
(相当于 onClick()
/onEvent()
)之外,还定义了两个特殊的事件:onCompleted()
和 onError()
。
onCompleted()
: 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的onNext()
发出时,需要触发onCompleted()
方法作为标志。onError()
: 事件队列异常。在事件处理过程中出异常时,onError()
会被触发,同时队列自动终止,不允许再有事件发出。- 在一个正确运行的事件序列中,
onCompleted()
和onError()
有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted()
和onError()
二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
三、RxJava的基础应用
1.最基本的应用(创建观察者与订阅者,并且通过注册实现关联)
//定义一个观察者 具体事件发布
Observable<String> mObservable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello, world! wusy");
subscriber.onCompleted();
}
});
//定义一个订阅者 具体行为操作
Subscriber<String> mSubscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.i(TAG, s.toString());
}
};
//观察者注册订阅者
mObservable.subscribe(mSubscriber);
也可以更简单实例化:
Observable.just("my rxjava").subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i(TAG, s.toString());
}
});
又或者:
Observable.just(“my rxjava”)
.subscribe(s -> Log.i(TAG,s.toString()));
2.RxJava中操作符简单应用
对于
RxJava的应用中,这个库无非强大的就是异步操作中,各种操作符的运用,这里笔者简单举例部分常见的操作符。
(1)just与from
使用场景:在有时候,我们发布的事件是多件,但是订阅者只需要一个即可,那么我们要写多个
Observable
吗?答案是:不需要。这里
RxJava提供了两个操作符,分别为:
just与from。两者实现功能是等价的,都可以同时初始化多个
Observable
,并且发布到同一个订阅者。具体实现方式如下:
Observable.just("1", "2", "3").subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i(TAG, s);
}
});
String[] datas = {"4", "5", "6"};//等价于 jsut(...)
Observable.from(datas).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i(TAG, s);
}
});
(2)强大的变换 map
使用场景,当我们发布一个事件的时候,例如发布的时候自带了一个网络图片链接,我们不希望在订阅者处理事件的时候,还要跑将url转化为Bitmap的逻辑(因为这样一定程度会消耗在主线程的事件,造成界面卡顿),因此我们希望有个机制可以帮我们将url转化成Bitmap,这就是操作符map的操作功能,具体实现如下:
String imgUrl = "";
Observable.just(imgUrl)
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String s) {
Bitmap bitmap = ToolUtils.url2Bitmap(s);
return bitmap ;
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {
imagview.
setImageBitmap(bitmap);}
});
(3)强大的变换flatMap
使用场景:在上面案例中Map只能做一对一的转化。假如有一个场景,在一个学生对象中,拥有属性课程,并且一个学生可以拥有多个课程信息。这里如果用map将学生转化为课程信息,明显这种一对多的场景map实用不了,因此我们也希望有个新的机制可以对一对多场景进行转化,具体实现如下:
List<Student> datas = new ArrayList<>();
for (int i = 0; i < 10; i++) {
String cuoursName = Integer.toString(i) + "同学课程";
String[] cours = {cuoursName, cuoursName, cuoursName, cuoursName, cuoursName, cuoursName, cuoursName, cuoursName, cuoursName};
Student student = new Student(Integer.toString(i) + "同学", cours);
datas.add(student);
}
Subscriber<String> mSubscriber = new Subscriber<String>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(String s) {
Log.i(TAG, s);
}
};
Observable.from(datas).flatMap(new Func1<Student, Observable<String>>() {
@Override
public Observable<String> call(Student student) {
Log.i(TAG, student.getName());
return Observable.from(student.getCours());
}
}).subscribe(mSubscriber);
读者阅读到这里,也许会觉得
flatMap比较难理解,笔者第一次接触的时候也相对觉得的确不好理解,如果你按照递归的方式去思考这个操作符,
flatMap与map唯一的去吧,就是回调call的时候还是返回了一个发布者
Observable
,因此在订阅者接收的时候,其实是多次性被触发了。
RxJava在Android应用中,现在并不是常见,但是这种观察者模式是比较典型一种事件分发模式。这里分享个一个开源,用RxJava写的RxEventBus,这里给出传送门,写的不错。
今天整理到这里,希望对读者有帮助
傻小孩b
20160331