一 、关于Rxjava
异步:RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。
简洁:异步操作很关键的一点是程序的简洁性,因为在调度过程比较复杂的情况下,异步代码经常会既难写也难被读懂。RxJava 的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。
二 、基本概念
- Observable:发射源,在观察者模式中称为被观察者
- Observer:接收源,在观察者模式中成为观察者,可接收Observable、Subject发射的数据;
- Subscriber:“订阅者”,也是接收源,接收源在观察者模式中成为观察者。Subscriber实现了Observer接口,比Observer多了一个最重要的方法unsubscribe( ),用来取消订阅。
- subscribe:订阅,Observable和Observer通过subscribe()进行订阅
- Subscription:Observable调用subscribe( )方法返回的对象,同样有unsubscribe( )方法,可以用来取消订阅事件;
-
Disposable
:用于维系观察者、被观察者之间的联系。 - Event:事件。
1、基本调用
添加依赖
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
创建被观察者
Observable normalObservable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter observableEmitter) throws Exception {
observableEmitter.onNext("msg1");//通过onNext(),发射一个"msg1"的String
observableEmitter.onNext("msg2");//通过onNext(),发射一个"msg2"的String
observableEmitter.onComplete();//发射完成,这种方法需要手动调用onCompleted,才会回调Observer的onCompleted方法
}
});
创建观察者
Observer mObserver = new Observer() {
@Override
public void onSubscribe(Disposable disposable) {
//d.dispose();移除订阅关系
//d.isDisposed()是否发生订阅关系
}
@Override
public void onNext(String s) {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
}
调用subscribe实现订阅
normalObservable.subscribe(mObserver);
2、链式调用
当然我们也可以使用链式操作的写法
其中Consumer参数的方法表示下游只对我们关心onNext事件,或Throwable事件进行处理
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter observableEmitter) throws Exception {
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
}
});
三、线程切换
我们在请求网络时必须是将其放在子线程执行,然后在安卓主线程中更新Ui
代码 | 含义 |
---|---|
Schedulers.immediate |
直接在当前线程运行。 |
Schedulers.newThread |
启用新线程,并在线程执行操作。 |
Schedulers.io |
内部是一个无数量上限的的线程池,可以重用空闲的线程,不要把计算工作放在io 中。 |
Schedulers.computation |
使用固定的线程池,大小为CPU 核数。 |
-
subscribeOn()
:指定Observable线程如
subscribeOn(Schedulers.io())
在IO线程中请求网络 -
observeOn()
:指定Observer线程如
observeOn(AndroidSchedulers.mainThread())
在主线程中更新界面
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
//模拟登陆
Call respCall = api.login(new User(username, password));
Resp resp = respCall.execute().body();
e.onNext(resp);
}
})
//设置请求网络在io线程内执行、子线程中执行
.subscribeOn(Schedulers.io())
//设置更新ui在安卓主线程中执行
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
//更新UI
}
});
四、操作符
操作符变换符是RxJava中一个很重要的概念,也是其简洁很重要的原因,这里整理一些很常见的操作符。
》》1.使用just( ),创建一个Observable并自动为你调用onNext( )发射数据(最多可发送9个)
Observable justObservable = Observable.just("just1","just2");//依次发送"just1"和"just2"
String []justs={"just1","just2"};
Observable.fromArray(justs)//传入数组,类似于just();
》》2.使用from( ),遍历集合,发送每个item
List list = new ArrayList<>();
list.add("from1");
list.add("from2");
list.add("from3");
Observable fromObservable = Observable.from(list); //遍历list 每次发送一个
注意:just()方法也可以传list,但是发送的是整个list对象,而from()发送的是list的一个item
》》3.使用defer( ),有观察者订阅时才创建Observable,并且为每个观察者创建一个新的Observable
Observable deferObservable = Observable.defer(new Func0>() {
@Override
//注意此处的call方法没有Subscriber参数
public Observable call() {
return Observable.just("deferObservable");
}});
》》4.使用interval( )创建一个按固定时间间隔发射整数序列的Observable,可用作定时器
Observable intervalObservable = Observable.interval(1, TimeUnit.SECONDS);//每隔一秒发送一次
》》5.使用range( ),创建一个发射特定整数序列的Observable,第一个参数为起始值,第二个为发送的个数,如果为0则不发送,负数则抛异常
Observable rangeObservable = Observable.range(10, 5);//将发送整数10,11,12,13,14
》》6.使用timer( ),创建一个Observable,它在一个给定的延迟后发射一个特殊的值,等同于Android中Handler的postDelay( )方法
Observable timeObservable = Observable.timer(3, TimeUnit.SECONDS); //3秒后发射一个值
》》7.使用repeat( ),创建一个重复发射特定数据的Observable
Observable repeatObservable = Observable.just("repeatObservable").repeat(3);//重复发射3次
》》8.使用concat( ),连接两个被订阅者,订阅者将会按照a->b
的顺序收到两个被订阅者所发射的消息。
final String[] aStrings = {"A1", "A2", "A3", "A4"};
final String[] bStrings = {"B1", "B2", "B3"};
final Observable aObservable = Observable.fromArray(aStrings);
final Observable bObservable = Observable.fromArray(bStrings);
Observable.concat(aObservable, bObservable);
输出A1", "A2", "A3", "A4","B1", "B2", "B3"
》》9.使用window( ),每隔n秒,发射这段时间内的数据,不是有数据就发射
Observable windowObservable=Observable.interval(1, TimeUnit.SECONDS).window(3, TimeUnit.SECONDS);//3秒后,发射前三秒所发射的数据
五、变换操作符
》》1. Map:最常用且最实用的操作符之一,将对象转换成另一个对象发射出去,应用范围非常广,如数据的转换,数据的预处理等。(如我们传入用户id需要查询用户信息,我们就可以使用map创建id返回user对象)
例一:数据类型转换,改变最终的接收的数据类型。假设传入本地图片路径,根据路径获取图片的Bitmap。
Observable.just(filePath).map(new Func1() {
@Override
public Bitmap call(String path) {
return getBitmapByPath(path);
}}).subscribe(new Action1() {
@Override
public void call(Bitmap bitmap) {
//获取到bitmap,显示
}});
例二:对数据进行预处理,最后得到理想型数据。实际开发过程中,从后台接口获取到的数据也许不符合我们想要的,这时候可以在获取过程中对得到的数据进行预处理(结合Retrofit)。
Observable.just("12345678").map(new Func1() {
@Override
public String call(String s) {
return s.substring(0,4);//只要前四位
}})
.subscribe(new Action1() {
@Override
public void call(String s) {
Log.i("mytag",s);
}});
》》2. FlatMap:和Map很像但又有所区别,Map只是转换发射的数据类型,而FlatMap可以将原始Observable转换成另一个Observable。
例:
需要使用的school类,student类就不展示了,保存一些学生基本信息的字段
public class School {
private String name;
private List studentList;
......
class studengt{
......
}
}
List schoolList = new ArrayList<>();
首先假设要打印全国所有学校的名称,可以直接用Map:
Observable.from(schoolList).map(new Func1() {
@Override
public String call(School school) {
return school.getName();
}}).subscribe(new Action1() {
@Override
public void call(String schoolName) {
Log.i(TAG,schoolName);
}});
再进一步,打印学校所有学生的姓名,先使用map
Observable.from(schoolList).map(new Func1() {
@Override
public School.Student call(School school) {
return school.getStudentList();//错误的地方
}}).subscribe(new Action1() {
@Override
public void call(School.Student student) {
Log.i(TAG,student.getName());
}});
看似可行,但事实上,这是一段错误的代码,细心的人就会发现错误的地方 school.getStudentList()返回的时list集合
Map是一对一的关系,无法将单一的School对象转变成多个Student。FlatMap可以改变原始Observable变成另外一个Observable,如果我们能利用from()操作符把school.getStudentList()变成另外一个Observable,现在使用FlatMap实现
Observable.from(schoolList).flatMap(new Func1>() {
@Override
public Observable call(School school) {
return Observable.from(school.getStudentList()); //关键,将学生列表以另外一个Observable发射出去
}}).subscribe(new Action1() {
@Override
public void call(School.Student student) {
Log.i(TAG,student.getName());
}});
》》3. Buffer:缓存,可以设置缓存大小,缓存满后,以list的方式将数据发送出去;例:
Observable.just(1,2,3).buffer(2).subscribe(new Action1>() {
@Override
public void call(List list) {
Log.i(TAG"size:"+list.size());
}});
运行打印结果如下:
MainActivity.this: size:2
MainActivity.this: size:1
Buffer和Map经常一起使用,通常发生在从后台取完数据,对一个List中的数据进行预处理后,再用Buffer缓存后一起发送,保证最后数据接收还是一个List,如:
List schoolList = new ArrayList<>();
Observable.from(schoolList).map(new Func1() {
@Override
public School call(School school) {
school.setName("NB大学"); //将所有学校改名
return school;
}}).buffer(schoolList.size()) //缓存起来,最后一起发送
.subscribe(new Action1>() {
@Override
public void call(List schools) {
}});
六 、过滤操作符
》》1.Take:发射前n项数据,还是用上面的例子,假设不要改所有学校的名称了,就改前四个学校的名称:
Observable.from(schoolList).take(4).map(new Func1() {
@Override
public School call(School school) {
school.setName("NB大学");
return school;
}}).buffer(4).subscribe(new Action1>() {
@Override
public void call(List schools) {
}});
》》2.Distinct:去掉重复的项,比较好理解
Observable.just(1, 2, 1, 1, 2, 3)
.distinct()
.subscribe(new Action1() {
@Override
public void call(Integer item) {
System.out.println("Next: " + item);
}
});
输出
Next: 1
Next: 2
Next: 3
》》3.Filter:过滤,通过谓词判断的项才会被发射,例如,发射小于4的数据
Observable.just(1, 2, 3, 4, 5)
.filter(new Func1() {
@Override
public Boolean call(Integer item) {
return( item < 4 );
}
}).subscribe(new Action1() {
@Override
public void call(Integer item) {
System.out.println("Next: " + item);
}});
输出:
Next: 1
Next: 2
Next: 3
》》window:
关于其他操作符或详情查看官网:RxJava使用以及操作符
六、注意事项
1、RxBinding的使用
RxBinding是在RxJava的基础上封装的一些操作,可以处理常用的一些UI的响应问题,这里具体实现就不分析了,只整理一些常用的方法作为记录。
添加依赖:
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha1'
1.1、常用方法:
1.1.1、RxView
-
RxView.clicks().throttleFirst(long windowDuration, TimeUnit unit)
指定的时间windowDuration
内,点击clicks
事件只响应一次 -
RxView.longClicks()
长按监听 -
RxView.draws()
绘制监听 -
RxView.drags()
拖拽监听 -
RxView.scrollChangeEvents()
滑动触发 - .....
例:按钮防抖,指定时间内事件只响应1次
//2秒内,按钮点击事件只响应1次
RxView.clicks(btn)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(new Consumer
1.1.2、RxTextView
-
RxTextView.textChanges()
EditText输入监听 -
RxTextView.textChangeEvents()
封装了TextWatcher文本改变的监听,返回数据的类型为TextViewTextChangeEvent,内部包含详细的文本改变数据。 -
RxTextView.editorActions()
监听了软键盘的回车点击 -
RxTextView.editorActionEvents()
监听了软键盘的回车点击,返回类型为TextViewEditorActionEvent。 - ......
例:监听文本变化
RxTextView.textChanges(et)
.subscribe(new Consumer() {
@Override
public void accept(CharSequence charSequence) throws Exception {
}
);
1.1.3、RxCompoundButton
RxCompoundButton.checkedChanges()
选中状态改变事件-
.....
RxView.clicks(btnLogin) .subscribe(o -> { RxCompoundButton.checked(cb).accept(true); })); RxCompoundButton.checkedChanges(cb) .subscribe(aBoolean -> { ...... });
2、避免内存泄漏
Activity被销毁时,我们的后台任务没有执行完,那么就会导致Activity不能正常回收,而对于每一个Observer,都会有一个Disposable对象用于管理。
在Observer
的onSubscribe
回调中,会传入一个Disposable
对象,下游可以通过该对象的dispose()
方法主动切断和上游的联系,在这之后上游的observableEmitter.isDisposed()
方法将返回true
。当上游和下游的联系切断之后,下游收不到包括onComplete/onError
在内的任何事件,若此时上游再调用onError
方法发送事件,那么将会报错。
为避免造成内存泄漏,我们需要将其将入到该集合当中,在Activity的onDestroy方法中,调用它的clear方法,就能避免内存泄漏的发生。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private CompositeDisposable compositeDisposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compositeDisposable=new CompositeDisposable();
Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter observableEmitter) throws Exception {
observableEmitter.onNext("msg");
}
});
DisposableObserver disposableObserver = new DisposableObserver() {
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
};
observable.subscribe(disposableObserver);
compositeDisposable.add(disposableObserver);
}
@Override
protected void onDestroy() {
compositeDisposable.clear();
super.onDestroy();
}
}