前言:
RxJava的介绍之前已经转载了2篇我认为写得比较清楚的。
这篇文章纯粹是我个人学习使用的Demo。
现在rx已经出2.0版本了,不过这里还是1.2的。
提供一下JakeWharton大神的git传送门:https://github.com/JakeWharton
写文章是为了自己在学习过程中梳理一下内容,做一下总结。
没啥文采,见笑。
本文主要内容为RxJava 1.2.1以下内容的使用Demo。
1、事件源的创建,通过Observable.create、from、just。以及Subject
2、过滤事件操作符的使用,包括filter、debounce。
3、线程切换,通过Scheduler类和AndroidSchedulers类。
4、事件转换操作符的使用,包括map、flatmap。
1.1 create
create的作用是创建一个事件源Observable,让它的监听者 Subscriber执行指定的方法。
Returns an Observable that will execute the specified function when a {@link Subscriber} subscribes to it.
Rx中声明了3种crate方法:
这里我只使用了最长用的第二种,另外两种看名字就差不多能猜出和数据同步有关系,比如读写数据库,调用一些有状态的函数等。
下面的代码创建了一个事件源,并让他的监听者弹一个内容为 createTest 的Toast。
Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("createTest"); } }).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Toast.makeText(Activity1.this,s, Toast.LENGTH_LONG).show(); } });
大体上,from可以接收3种参数类型,Future、Iterable(list)、数组,它也是通过Obeservable读取每个元素然后发出事件。
下面的代码,在空间content上写下3行字:
I have 烂剧本
I have 小鲜肉
啊 小时代
List<String> list = new ArrayList<>(); list.add("I have 烂剧本 \n"); list.add("I have 小鲜肉 \n"); list.add("阿 小时代\n"); Observable.from(list) .subscribe(new Subscriber<String>() { @Override public void onCompleted() { content.setText(fromContentStr.toString()); unsubscribe(); } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.d("thm", "onNext s = "+s); fromContentStr.append(s); } }); }
just和from类似,它依次把每个参数作为事件发出去,最多可以有10个参数。
下面的代码在空间content上写下3行字:
I have LOL
I have 路由器
啊 杨教授又多一病例
Observable.just("I have LOL\n", "I have 路由器\n", "啊 杨教授又多一病例\n") .subscribe(new Subscriber<String>() { @Override public void onCompleted() { content.setText(fromContentStr.toString()); unsubscribe(); } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.d("thm", "onNext s = "+s); fromContentStr.append(s); } });
1.4 Subject
Subject是Observable和Observer的集合体,继承了Observable,实现了Observer,
即它即是观察者,也是被观察者。
Subject subject = PublishSubject.create(); subject.subscribe(new Subscriber() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Object o) { } }); subject.onNext(new Object());
1.5 subscribe() 订阅方法。只有调用了订阅后,Observable才会开发发送事件,如下的onSubscribe.call()
public Subscription subscribe(Subscriber subscriber) { subscriber.onStart(); onSubscribe.call(subscriber); return subscriber; }onStart是一个可选方法,默认的实现为空。
可以重写onStart来做一些诸如统计、初始化、打日志之类的事情。
2.1 filter
顾名思义,filter的作用就是过滤,事实也的确如此。
Filters items emitted by an Observable by only emitting those that satisfy a specified predicate. return an Observable that emits only those items emitted by the source Observable that the filter evaluates as {@code true}筛出根据predicate条件判断为true的项
下面的代码过滤掉原始Observable中的奇数项。
Integer ints[] = {1,2,3,4,5,6,7,8,9,10};
Observable.from(ints) .filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer ints) { return ints%2 == 0; } }) .subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { Log.d("thread", "testFilter onCompleted"+Thread.currentThread()); content.setText(fromContentStr.toString()); unsubscribe(); } @Override public void onError(Throwable e) { } @Override public void onNext(Integer integer) { Log.d("thread", "testFilter onNext"+Thread.currentThread()); fromContentStr.append("filter过滤单数"+integer+"\n"); } });
这个api可以用来防止重复操作。它会过滤掉指定时间内的其它事件。
注意:它是过滤掉前面的,保留最后一个!
If items keep being emitted by the source Observable faster than the timeout then no items will be emitted by the resulting Observable.因此,下面的代码是从1,2,3,4,5,6,7,8,9,10中过滤掉偶数项。
Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (Integer i : ints) { if(i%2==0){ try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } subscriber.onNext(i); } subscriber.onCompleted(); } }) .debounce(10, TimeUnit.MILLISECONDS) .subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { content.setText(fromContentStr.toString()); Log.d("thread", "testDebounce onCompleted"+Thread.currentThread()); unsubscribe(); } @Override public void onError(Throwable e) { Log.d("thm", "testDebounce onError msg = "+e.getMessage()); } @Override public void onNext(Integer integer) { Log.d("thread", "testDebounce onNext"+Thread.currentThread()); fromContentStr.append("debounce过滤双数"+integer+"\n"); } });
3.指定运行的线程
subscribeOn(Schedulers)来指定事件源的执行线程。
observeOn(Schedulers)来指定观察者的执行线程。
下面是一种最常见的使用场景,在Scheduler.io()中解析数据,在UI线程中更新界面。
基本上所有的后台线程取数据,UI线程做显示的工作都是这样切换线程的。
RetrofitHelper.getInstance() .getGiftList(friendid,userid) // Observable<GiftDataResponse<GiftData<GiftBean>>> .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<GiftDataResponse<GiftData<GiftBean>>>() { @Override public void onCompleted() { LogUtil.d("retorfitHelper getGifts onCompleted"); } @Override public void onError(Throwable e) { //do error } @Override public void onNext(GiftDataResponse<GiftData<GiftBean>> httpResponse) { //do sth } });
private AndroidSchedulers() { RxAndroidSchedulersHook hook = RxAndroidPlugins.getInstance().getSchedulersHook(); Scheduler main = hook.getMainThreadScheduler(); if (main != null) { mainThreadScheduler = main; } else { mainThreadScheduler = new LooperScheduler(Looper.getMainLooper()); } }AndroidScheduler.mainThread()就是安卓的UI线程。
Scheduler还有以下获取线程api:
*Scheduler.immediate() :在当前线程运行,即默认状态
*Scheduler.newThread() :启用一个新线程来执行
*Scheduler.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler
。行为模式和 newThread()
差不多,区别在于 io()
的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io()
比 newThread()
更有效率。
*Scheduler.computation:用于CPU密集型计算,如图像计算。
注意:不要在io中做计算操作,也不要在computation中做io操作。前者会创建不必要的线程,后者会消耗不必要的CPU资源。
4.使用事件转化操作符做嵌套操作
RxJava中主要有3种事件转化操作符,分别为map、flatmap和compse。
4.1 map
map是对象间的转换,比如下面的函数testmap中map是把Integer转成String。
依次把String发出去,最后在content中打印出 “I hava 银子, I have 通宝, 嗯?哼?->同城游”。
Integer ints[] = {1,2,3,4,5,6,7,8,9,10}; String s[] = {"I have ","银子, " ,"I have ", "通宝, ","嗯?","哼?", "->", "同城游"}; private StringBuffer fromContentStr = new StringBuffer(); private void testMap(){ Observable.from(ints) .map(new Func1<Integer, String>() { @Override public String call(Integer i) { return s[i-1]; } }) .subscribeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.d("thm", "on Next s = "+s); fromContentStr.append(s); content.setText(fromContentStr.toString()); } }); }
4.2 flatmap
flatmap是把事件转成一个新的事件源Obervable。
比如下面的代码,通过flatmap将Observable<home>转成Observable<String>,
最后在content上打印出
dad, mom, me
dad, mom, me, brother
home homes[] = {new home(new String[]{"dad, ", "mom, ", "me\n"}), new home(new String[]{"dad, ", "mom, ", "me, ", "brother\n"})}; private void testFlatmap(){ Observable.from(homes) .flatMap(new Func1<home, Observable<String>>() { @Override public Observable<String> call(home home) { return Observable.from(home.members); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<String>() { @Override public void onCompleted() { content.setText(fromContentStr.toString()); } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { fromContentStr.append(s); } }); } class home{ String members[]; public home(String s[]){ members = s; } }
结语
这里是我认为RxJava中最常用的api的使用demo。
打算下一篇中总结一下Rx中不是特别常用的那些api,以及配合Retrofit进行网络请求的使用。