什么是RxAndroid
RxAndroid是现在比较流行的针对Android的开源RxJava库。主要用于实现异步的响应式编程。RxAndroid使用了观察者模式,通过定义被观察者Observable和使用Observable的subscribe进行订阅操作绑定观察者,对Observable的事件进行监听。当Observable发生变化或发送数据时就会通知所有订阅了该Observable的Observer。
RxAndroid的基本使用方式
Observable.just(1, 2, 3)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
这里使用Observable的just方法构建一个被观察者。just可以快速构建一个依次发送多个数据的Observable。
调用subscribe方法对创建的Observable进行订阅,Observer的onSubscribe方法在订阅时调用;每发送一个数据都会调用onNext方法,onNext的参数类型就是定义Observer的泛型,当发送出现错误时就会调用onError方法;一次事件完成后会调用onComplete方法表示一次事件的完成。
RxAndroid常用操作符
创建Observable
create
创建Observable时的方法,需要实现ObservableOnSubscribe接口,然后在ObservableOnSubsceibe接口的subscribe方法中实现订阅逻辑如下:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("a");
emitter.onNext("b");
emitter.onComplete();
}
});
定义一个简单的被观察者,当有观察者订阅时会调用观察者的onNext方法依次传递a和b然后结束本次事件。
just
创建一个依次发送指定参数的Observable
Observable.just(a,b).subscribe(new Consumer<String>(){
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "onNext: "+s );
}
});
这个被观察者的效果同上面的一样发送a和b后结束事件
amb和ambArray
传递多个Observable,但只有最早产生事件的Observable的事件会被消费,其他会被抛弃。
Observable.amb(Iterable<? extends ObservableSource<? extends T>> sources)需要传递一个Observable的迭代器的参数
Observable.ambArray (ObservableSource<? extends T> … sources)需要传递多个Observable对象
下面是ambArray的简单使用
Observable.ambArray(
Observable.just(1).delay(100, TimeUnit.MILLISECONDS),
Observable.just(2)
).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept: "+integer);
}
});
传递两个使用just方法生成的Observable,但是第一个调用了Observable的delay方法使事件延迟发送,这里是延迟0.1秒。由于ambArray只消费第一个产生事件的Observable所以最后输出的是2。
amb和ambArray可以使用在同时向多个ip发起请求,最快响应的那个服务器将作为后续访问的节点。
concat
concat可以使传递过来的Observable进行串行执行。即上一个Observable触发onComplete或onError后,下一个Observable才开始执行。
下面是concat的所有原型方法,参数不同不过效果基本一样
static <T> Observable<T> concat(Iterable<? extends ObservableSource<? extends T>> sources);
static <T> Observable<T> concat(ObservableSource<? extends ObservableSource<? extends T>> sources, int prefetch);
static <T> Observable<T> concat(ObservableSource<? extends T> source1, ObservableSource<? extends T> source2, ObservableSource<? extends T> source3, ObservableSource<? extends T> source4)
static <T> Observable<T> concatArray(ObservableSource<? extends T>... sources);
static <T> Observable<T> concatArrayDelayError(ObservableSource<? extends T>... sources);
static <T> Observable<T> concatArrayEager(int maxConcurrency, int prefetch, ObservableSource<? extends T>... sources);
static <T> Observable<T> concatArrayEagerDelayError(int maxConcurrency, int prefetch, ObservableSource<? extends T>... sources);
static <T> Observable<T> concatDelayError(ObservableSource<? extends ObservableSource<? extends T>> sources, int prefetch, boolean tillTheEnd);
static <T> Observable<T> concatEager(Iterable<? extends ObservableSource<? extends T>> sources, int maxConcurrency, int prefetch);
以一个演示一下简单的用法:
Observable.concat(
Observable.just("a"),
Observable.just("b")
).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG,"accept:"+ s);
}
});
当然此处只是简单的演示参数的传递和调用,实际使用应该是几个进行复杂操作的Observable的串型调用
merge
merge是并行的触发所有的Observable,当所有子Observable都结束事件调用onComplete方法后才会触发onComplete结束事件
Observable.merge(
Observable.just(1).delay(1000, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread()),
Observable.just(2).delay(500,TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread()),
Observable.just(3).delay(800,TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread())
).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept: " + integer);
}
});
定义三个Observable并给予不同延时,由于是并行执行需要使用subscribeOn方法手动设置不同的线程进行调度,执行后可以看到依次输出 2 3 1,由于是并行执行所以延时最短的将最早输出
range
定义一个Observable指定输出初始值n和数量m输出大于等于n的m个数
Observable.range(5,10)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept: "+ integer);
}
});
Observable事件加工
filter
定义过滤器过滤不符合条件的数据。
Observable.just(2,4,5,7,8,9).filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) throws Exception {
return integer > 6;
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept: "+integer);
}
});
map
拦截Observable发射出来的事件,并将事件的数据转化成其他数据后再发射到Observable中
Observable.just(2,4,5,7,8,9)
.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return "this is "+ integer;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "accept: "+ s);
}
});
使用just定义一个发送integer类型数据的Observable,然后使用map方法将integer转化成需要输出的String类型的数据再进行发送。
flatMap
拦截Observable发射的事件,并将数据转化成Observable对象后通过这些新生成的Observable取代原有的Observable提供数据
下面是网上找的一个演示flatMap用法的例子:
假设有一群小朋友聚在一起玩耍,每个人都需要拿出自己的玩具,然后我们需要统计下这些玩具,代码如下:
class Toy {
String name;
Toy(String name) {
this.name = name;
}
}
class Kid {
List<Toy> toys;
}
List<Kid> kids() {
List<Kid> kids = new LinkedList<>();
Kid kid = new Kid();
kid.toys = new LinkedList<>();
kid.toys.add(new Toy("熊大"));
kid.toys.add(new Toy("熊二"));
kids.add(kid);
kid = new Kid();
kid.toys = new LinkedList<>();
kid.toys.add(new Toy("水枪"));
kids.add(kid);
kid = new Kid();
kid.toys = new LinkedList<>();
kid.toys.add(new Toy("足球"));
kid.toys.add(new Toy("扭扭车"));
kids.add(kid);
return kids;
}
void test() {
Observable.fromIterable(kids())
.flatMap(new Function<Kid, ObservableSource<Toy>>() {
@Override
public ObservableSource<Toy> apply(Kid kid) throws Exception {
return Observable.fromIterable(kid.toys);
}
}).subscribe(new Consumer<Toy>() {
@Override
public void accept(Toy toy) throws Exception {
Log.i(TAG, "accept: "+toy.name);
}
});
}
上述例子就是通过flatmap将原来的泛型为kid集合的Observable转化成toy集合的Observable然后再对这新的Observable进行订阅
take
take将指定最多输出数据的数量
Observable.just(1, 2, 3, 4, 5, 6)
.take(3)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept: ");
}
});
由于take的值是3所以将只输出1,2,3
doOnNext
在每次输出一个元素之前额外做一些事情
Observable.just(1, 2, 3, 4, 5, 6)
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept1: " + integer);
}
})
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "accept2: "+integer);
}
});
与这个差不多的还有doOnSubscribe,doOnComplete,doOnError分别在对应的方法前在进行一些操作
subscribeOn和observeOn
subscribeOn:设置Observable被观察者的运行线程
observeOn:设置Observer观察者运行的线程
Observable.just(1,2,3,4,5)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
}
});
这里是比较常用的两种指定线程,将Observable设置在io线程,Observer设置在ui线程,这样就能够实现Observable中进行网络请求或图片加载等耗时操作,执行完后切换到UI线程进行界面的更新
compose
将对当前的Observable进行操作,可以将原来的Observable转化成新的Observable
使用compose操作可以减少需要对Observable进行的重复操作
ObservableTransformer<Integer,Integer> transformer = new ObservableTransformer<Integer, Integer>() {
@Override
public ObservableSource<Integer> apply(Observable<Integer> upstream) {
return upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
Observable.just(1,2,3,4,5)
.compose(transformer)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
}
});
声明一个ObservableTransformer 对Observable设置subscribeOn和observeOn,这样所有需要Observable在io线程执行,Observer在ui线程执行的Observable都可以通过compose这个ObservableTransformer进行进行操作减少部分重复的代码
实战练习
下面是学习时使用RxAndroid和retrofit进行网络请求是案例
retrofit的接口类
public interface GirlApi {
@GET("data/福利/10/{page}")
Observable<Result<GirlData>> fetchPrettyGirl(@Path("page") int page);
}
public class GirlRetrofit {
private static final String GANK_URL = "http://gank.io/api/";
private final GirlApi mGirlApi;
public GirlRetrofit(){
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(20, TimeUnit.SECONDS);
builder.readTimeout(15,TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GANK_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(builder.build())
.build();
mGirlApi = retrofit.create(GirlApi.class);
}
public GirlApi getGirlApi(){
return mGirlApi;
}
}
进行网络请求
private Function<? super GirlData, ? extends ObservableSource<? extends List<Image>>> imageFetcher
= new Function<GirlData, ObservableSource<? extends List<Image>>>() {
@Override
public ObservableSource<? extends List<Image>> apply(GirlData girlData) throws Exception {
for (PrettyGirl girl : girlData.results) {
try {
Bitmap bitmap = Picasso.get().load(girl.url).get();
Image image = new Image();
image.width = bitmap.getWidth();
image.height = bitmap.getHeight();
image.url = girl.url;
Log.w(TAG, "apply: imageUrl" + image.url);
mImageList.add(image);
} catch (IOException e) {
e.printStackTrace();
}
}
return Observable.just(mImageList);
}
};
private void fetchGirlData() {
Observable<List<Image>> results = mGirlApi.fetchPrettyGirl(page)
.compose(this.<Result<GirlData>>bindToLifecycle())//绑定生命周期
.filter(new Predicate<Result<GirlData>>() {
@Override
public boolean test(Result<GirlData> girlDataResult) throws Exception {
return !girlDataResult.isError() && girlDataResult.response().isSuccessful();
}
})//过滤掉请求失败的数据
.map(new Function<Result<GirlData>, GirlData>() {
@Override
public GirlData apply(Result<GirlData> girlDataResult) {
return girlDataResult.response().body();
}
})//将获取到的Result数据转化成model类
.flatMap(imageFetcher)//对获取到的数据进行处理添加到mImageList中,再将Observable转化成Image集合类型的Observable
.subscribeOn(Schedulers.io())//定义数据获取是在Io线程中执行
.observeOn(AndroidSchedulers.mainThread())//由于最后涉及到ui操作需要将observer的操作定义在ui线程
.cache();
results.filter(new Predicate<List<Image>>() {
@Override
public boolean test(List<Image> o) throws Exception {
return o.size() != 0;
}
})//如果集合的size为0就过滤掉不进行操作
.compose(this.<List<Image>>bindToLifecycle())
.doOnComplete(new Action() {
@Override
public void run() throws Exception {
mBinding.refreshLayout.setRefreshing(false);
}
})//当数据更新结束后将refreshLayout的刷新状态改成false
.subscribe(new Consumer<List<Image>>() {
@Override
public void accept(List<Image> images) throws Exception {
mAdapter.notifyDataSetChanged();//通知recyclerView的Adapter数据集合发生改变。刷新显示
mBinding.refreshLayout.setRefreshing(false);
}
}, dataError);
}