Rxjava是一个异步框架,它是基于观察者模式(简单来说,就是观察者监视被观察者,当被观察者进行动作的时候,被观察者做出反应)。其主要优点在于结构化,使用它可以使你的代码更加简洁。
首先导包,我是用了Retrofit里的Rxjava
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
也可以导专门做Rxjava的包
compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'
- 一个简单例子
public void testrxjava(){
//创建观察者
Observer<String> observer=new Observer<String>() {
//被观察者完成后回调
@Override
public void onCompleted() {
Log.d("completed","完成");
}
//出错时回调
@Override
public void onError(Throwable e) {
}
//进行时回调
@Override
public void onNext(String s) {
Log.d("onNext",s);
}
};
//创建被观察者
Observable observable=Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("步骤1");
subscriber.onNext("步骤2");
subscriber.onCompleted();
}
});
//通过订阅来绑定观察者与被观察者
observable.subscribe(observer);
}
上面的代码就是一个最简单的Rxjava,但是并没有什么用,它一般是写成匿名类的方式,博文后面也都是采用匿名类的方式来写代码的。再介绍一个类Subscriber,它与Observer用法一样,只不过除了上述三个方法还多了个可重写的方法onStart(在观察者刚开始,事件还没有传递时调用,用于做一些准备工作),后面有些地方用的是这个类。
- 创建、重做、重试.
先说说创建
1、form方式创建,传入一个集合,Observer会把集合的item一个个读出来
Observable.from(new String[]{"123","abc"}).subscribe(new Observer<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.d("onNext",s);
}
});
2、just方式创建,just里面可以传多个对象进去,所传对象不是同一种对象是用Serializable对象来处理数据。
Observable.just("3",3).subscribe(new Subscriber<Serializable>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Serializable serializable) {
Log.d("onNext",serializable.toString());
}
});
3、create创建,如上述的简单例子,直接创建一个被观察者对象
4、interval创建,创建一个指定时间间隔发送序列号的对象,可用于倒计时。
//每毫秒进行一次操作
Observable<Long> observable=Observable.interval(1, TimeUnit.MILLISECONDS);
observable.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Long aLong) {
Log.d("onNext",aLong.toString());
if(aLong>=2000) this.unsubscribe();
}
});
还有:timer创建,延迟指定时间发送一条数据(固定为 0);
rang创建,发送一定范围类连续整数
empty创建,不发送任务数据,直接回调oncompleted
error创建,不发送任务数据,直接回调onerror
never创建,什么也不发送,什么也不回调
defer创建,每次订阅的时候创建一个对象。
重做:
repeat,observable重复发送onnext数据通知,次数达到后才发送oncompleted通知
Observable<Long> observable=Observable.interval(1, TimeUnit.MILLISECONDS);
observable.repeat();//重做无限次
observable.repeat(3);//重做三次
repeatwhen,在发送一个onnext通知后,根据条件确定是否重复发送。
重试:
retry,在observable出现异常是不发送onerror通知而是,重新订阅observable,直到不出现异常或者重试次数达上限,用法与repeat类似。
retryWhen,有条件的重试。
- Action和Func
对于之前的observer,都必须重写三个函数,有时我们并不需要重写三个函数,这个时候就得用到action了。action可以看成是一个只有一个方法的observer,它分为action0和actionX(x为几则表示有几个参数),action0没有参数,action1只有一个参数,而且订阅的时候可以绑定多个action(限定第一个位置只能具备泛型的actionX,第二个位置只能Throwable类型的actionX,第三个action0),这样,我们使用起来就很自由了。一般情况只用第一个位置就行了。
Action1<String> action1=new Action1<String>() {
@Override
public void call(String s) {
Log.d("action1",s);
}
};
Action1<Throwable> action2=new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
};
Action0 action0=new Action0() {
@Override
public void call() {
}
};
Observable.just("3","3").subscribe(action1,action2,action0);
}
func与action只有一点区别,func有返回值,常用与转换,action没有返回值。
- 转换、过滤、合并
转换:
map,将一种类型转换成另一种类型后再发送,而且可以多次调用这个方法,进行多次转换。
Observable.just("abcd","123").map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return s.length();
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d("call",String.valueOf(integer));
}
});
flatmap,这个转换的返回值是一个observable,也就是把开始那个observable发送的数据,我自己拿到再以我自己的方式发送。下面这个例子,用flat的目的是,避免observer中使用for嵌套。但是,flatmap是对之前那个observer发送来的数据做合并,而且是交错的,也就是不能保证顺序。
ArrayList<String> s=new ArrayList<String>();
s.add("a");
s.add("b");
s.add("c");
Observable.just(s).flatMap(new Func1<ArrayList<String>, Observable<?>>() {
@Override
public Observable<?> call(ArrayList<String> strings) {
Observable<String> obs=Observable.from(strings);
return obs;
}
}).subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
Log.d("call", (String) o);
}
});
转换还有:flatMapIterable对原来的数据进行打包发送,
concatMap放回有次序的observable
switchMap只发送最新数据,一般有延时才能看出来。
过滤:filter,自己设置过滤条件来过滤掉observable发送的数据,下面这个例子是过滤掉长度小于等于3的字符串。
Observable.just("123","abcd").filter(new Func1<String, Boolean>() {
@Override
public Boolean call(String s) {
if(s.length()>3) return true;
return false;
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.d("call",s);
}
});
take,取前几项,其他的过滤掉,takelast则是取后几项
Observable.just("123","abcd").take(1)
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.d("call",s);
}
});
skip,与take相反,过滤掉前几项,其他保留,skiplast过滤掉后几项。与take用法一样
elementAt,只发送第几项,其他过滤。与take用法一样。
distinct去除重复项,distinctUtilChanged去除相邻重复项,它们不需要传参,直接调用。
合并:
merge,合并两个observable对象,头尾先接的合并,然后发送。
Subscription sub= Observable.merge(Observable.just(1,2),Observable.just(3,4))
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d("merge", String.valueOf(integer));
}
});
sub.unsubscribe();
在这个例子中,其实observable调用订阅方法subscribe是会返回一个订阅对象subscription的,拿到这个对象有什么好处呢?就是我可以随时取消掉订阅。
zip:将里面的多个observable按自己的方式结合起来,每个observable的第i个数据结合,以数据最少的那个observable为准,其他observable多余数据舍弃。如下述例子的log为 a1和b2,c舍弃了。
Observable.zip(Observable.just(1, 2, 3), Observable.just("a", "b"), new Func2<Integer, String, Object>() {
@Override
public Object call(Integer integer, String s) {
return s+integer;
}
}).subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
Log.d("zip", (String) o);
}
});
- Scheduler线程控制
上述写了怎么多,感觉都没什么用,那是还没有用上Rxjava最关键的技术-异步。Rxjava的强大之处可以指定在什么线程进行什么操作。介绍两个方法
subscribeOn():用于指定事件产生的线程,也就是被观察者所处的线程,像文件访问、网络请求的时候被观察者进行阻塞操作,就需要用它指定线程。
observeOn():用于指定事件消费的线程,也就是观察者所处的线程,对于上述阻塞操作的结果处理需要用它指定线程,通常是主线程。
方法里面的参数即所指线程用这么几个:
Schedulers.immediate():当前线程,默认都是当前线程
Schedulers.newThread():开启一个新的线程
Schedulers.io():IO操作所用的线程
AndroidSchedulers.mainThread():主线程。
Observable.just(1,2)
.subscribeOn(Schedulers.newThread())//触发事件在新线程中执行
.observeOn(Schedulers.newThread())//之后的操作都在新线程执行
.map(new Func1<Integer, Object>() {
@Override
public Object call(Integer integer) {
return null;
}
}).subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
}
});
其实observeOn是指定后续所有操作的线程,如上述例子,加入我消费事件和map不想在同一线程怎么办呢?那么只要在subscribe方法之前再调用一次方法指定线程就可以了。也就是说可以多次调用observeOn方法来切换线程。
看到这里是不是感觉Rxjava特别强大。
这里只介绍了部分常用的操作符,想要知道更多操作符可以查看文档:Rxjava文档,不想看文档就自行百度Rxjava操作符大全吧。