文章目录
前言
RXJava是基于观察者模式开发的一个开源库,这里的观察者模式与生活中正常的观察者模式是相反的, 生活中的观察者模式是 观察者主动观察被观察者,在被观察者发生变化的时候进行相应处理,例如老师与学生。计算机编程中观察者模式,是需要被观察者主动来报告自定的状态的,在被观察者发生了变化的时候主动通知观察者。这里就出现了订阅和通知与解除订阅三种动作。
实现观察者模式需要以下几步:
- 1 创建一个被观察对象Observable
- 2 被观察者主动订阅观察者subscribe
- 3 在被观察者发生变化的时候,通知观察者进行处理 doOnNext
- 4 不使用观察者模式的时候,被观察者解除与观察者之间的订阅关系。
关于RxJava的说明及更多使用请查看下面两个博客,本篇只进行常用的使用说明。
给 Android 开发者的 RxJava 详解
https://gank.io/post/560e15be2dca930e00da1083
RxJava2.0——从放弃到入门
https://www.jianshu.com/p/cd3557b1a474
环境配置
在项目的app下的build.gradle
文件中添加如下配置, 这里因为后面需要演示如何与Retrofit2
配合使用,所以也添加了Retrofit2
的配置
//RxJava
implementation 'io.reactivex:rxjava:1.1.6'
implementation 'io.reactivex:rxandroid:1.2.0'
//Retrofit 2.0.0-beta2
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.okhttp:okhttp:2.5.0'
implementation 'com.squareup.okio:okio:1.6.0'
implementation 'com.google.code.gson:gson:2.4'
implementation 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
implementation "com.squareup.retrofit2:adapter-rxjava:2.1.0"
Observable
简单的订阅与观察
String[] args = {"a", "b", "c"};
//简单示例,在IO线程上实现订阅和观察
Observable.from(args)
.subscribeOn(Schedulers.io()) //指定在哪个线程上实现订阅
.observeOn(Schedulers.io()) //指定在哪个线程上实现观察
.doOnNext(new Action1<String>() {
@Override
public void call(String s) {
//因为观察指定在IO线程,所以这里如果进行UI操作,将会引发异常
Log.i("RxDemo", s);
}
}).subscribe();
运行程序,输出如下:
I/RxDemo: a
I/RxDemo: b
I/RxDemo: c
这里我们需要注意的是,因为我们在代码里指定了订阅
行为发生在IO线程
上进行,也就是说被观察者执行的操作是在IO线程上的
,观察者
被指定了通知接收行为发生在IO线程
, 被观察者
发送的通知回调是在io线程
上的,这里是不能在通知函数doOnNext
中进行UI操作的,否则会引发异常的。
线程间切换
Observable.from(args)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())//在UI线程上进行观察
.doOnNext(new Action1<String>() {
@Override
public void call(String s) {
//如果需要进行UI操作,观察者需要切换到UI线程上进行观察
Toast.makeText(getBaseContext(), s,
Toast.LENGTH_SHORT).show();
}
}).subscribe();
这里我们在代码里指定了订阅
行为发生在主线程
上进行,也就是说被观察者执行的操作是在主线程
上的,观察者
被指定了通知接收行为发生在主线程
, 被观察者
发送的通知回调是在主线程
上的,所以这里可以在通知函数doOnNext
中进行UI操作的,不会引发异常的。
完整生命周期
Observable.from(args)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Action1<String>() {
@Override
public void call(String s) {
Log.i(TAG, s);
}
})
.doOnSubscribe(new Action0() {
@Override
public void call() {
Log.i(TAG, "doOnSubscribe-->开始加载");
}
})
.doOnTerminate(new Action0() {
@Override
public void call() {
Log.i(TAG, "onTerminate-->加载完成");
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
Log.i(TAG, "onCompleted-->结束加载");
}
})
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.i(TAG, "发生异常了,异常错误是: " +
throwable.getMessage());
}
})
.doAfterTerminate(new Action0() {
@Override
public void call() {
Log.i(TAG, "doAfterTerminate-->流程走完了");
}
})
.subscribe();
整个观察者周期一共会调用以下的函数
doOnSubscribe
在订阅创建完成以后就会被调用doOnNext
在Obserable调用onNext
之后进行调用doOnTerminate
在Obserable调用onCompleted
之前进行调用。doOnCompleted
在Obserable调用onCompleted
之后调用doOnError
在Obserable调用onError
之后调用,流程被中断。doAfterTerminate
在Obserable调用onCompleted
之后进行调用。
这里onError
和onCompleted
是互斥的,同一个流程中,只有一个会被调用。
运行程序,日志输入如下:
I/RxDemo: doOnSubscribe-->开始加载
I/RxDemo: a
I/RxDemo: b
I/RxDemo: c
I/RxDemo: onTerminate-->加载完成
I/RxDemo: onCompleted-->结束加载
I/RxDemo: doAfterTerminate-->流程走完了
异常处理
Observable.from(args)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(new Action0() {
@Override
public void call() {
Log.i(TAG, "doOnSubscribe");
}
})
.doOnTerminate(new Action0() {
@Override
public void call() {
Log.i(TAG, "doOnTerminate 在OnError之前调用");
}
})
.doAfterTerminate(new Action0() {
@Override
public void call() {
Log.i(TAG, "doAfterTerminate 在OnError之后调用");
}
})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i("RxDemo", s);
int a = 1 / 0;
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.i(TAG, "发生异常了,异常错误是: " +
throwable.getMessage());
}
}, new Action0() {
@Override
public void call() {
Log.i(TAG, "onComplete");
}
});
运行程序,日志输入如下:
I/RxDemo: doOnSubscribe
I/RxDemo: a
I/RxDemo: 发生异常了,异常错误是: divide by zero
上面这个示例表明,如果在doOnNext
中发生了异常,则会出现doOnError
,因为业务被中断了,所以不会调用doOnTerminate
、doOnCompleted
、doAfterTerminate
。
Observable管理
RxJava提供了CompositeSubscription对Observable进行管理,例如:
compositeSubscription.add(observable)
的方式对Observable
进行管理。compositeSubscription.clear()
清空并停止所有正在执行的Observable
简单示例
//对Observable进行管理
private CompositeSubscription compositeSubscription = new CompositeSubscription();
compositeSubscription.add(
Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(time -> {
if(null == mActivity){
KLog.i("mActivity is null");
compositeSubscription.clear();
}else{
KLog.i("mActivity is not null");
}
}, throwable ->
KLog.i("occour exception, " +
throwable.getMessage())
)
);
RXJava与Retrofit结合使用
Retrofit是一个注解式的网络请求框架,自身与OKHttp结合能够轻便快捷的实现多种网络请求。与RXJava结合使用后更是如虎添翼,轻松实现网络请求的网络切换与链式编程。
定义Retrofit接口类
import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;
public interface PoetryTestAPI {
@GET("/getSongPoetry")
Observable<PoetryList> getPoetryList(@Query("page") int page, @Query("count") int count);
}
初始化Retrofit类
/*这里统一使用retrofit2,所以配置中需要同已修改为retrofit2的配置,
包含retrofit, convert-gson、adapter-rxjava, 具体配置请查看签名的`环境配置`
*/
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.apiopen.top")
//添加Gson转换适配器
.addConverterFactory(GsonConverterFactory.create())
//添加RxJava适配器
.addCallAdapterFactory(
RxJavaCallAdapterFactory.create())
.build();
PoetryTestAPI poetryTestAPI =
retrofit.create(PoetryTestAPI.class);
简单的网络请求
poetryTestAPI.getPoetryList(1, 10)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(() -> {
Log.i(TAG,"开始加载数据...");
})
.doOnTerminate(() ->{
Log.i(TAG,"数据加载完成,正在解析...");
})
.doOnCompleted(() -> {
Log.i(TAG,"数据加载完毕!!");
})
.doAfterTerminate(() -> {
Log.i(TAG,"数据查询完毕!!");
})
.subscribe(new Action1<PoetryList>() {
@Override
public void call(PoetryList poetryList) {
Log.i(TAG,"doOnNext");
if(null != poetryList) {
Log.i(TAG, new Gson().toJson(poetryList));
}
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.i(TAG, "发生异常了,异常错误是: " +
throwable.getMessage());
}
});
运行程序,输入如下:
开始加载数据...
doOnNext
{"code":200,"message":"成功!","result":[{"authors":"宋太祖","content":"欲出未出光辣达,千山万山如火发。|须臾走向天上来,逐却残星赶却月。","title":"日诗"}, ...]}
数据加载完成,正在解析...
数据加载完毕!!
数据查询完毕!!
优化网络请求
定义一个转换器
/*
* 定义一个转换器,用于实现订阅者和观察者之间的线程切换
* Observable.Transformer<T, R>
* @param <T> the first argument type
* @param <R> the result type
* */
Observable.Transformer<Object, Object> composeTransformer =
observable -> observable.throttleFirst(
500, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
使用Lamdba表达式
1 这里如果报错提示你需要使用Lamdba表达式,需要使用jdk1.8, 否则会报错提示
**Lamdba express are not supported at language level ‘7’ **
2 Lamdab表达式格式 ‘(参数列表) -> { 代码块 }’ 或者 ‘参数名 -> { 代码块 }’
poetryTestAPI.getPoetryList(1, 10)
.compose(composeTransformer)
.doOnSubscribe(() -> Log.i(TAG, "开始执行数据!!"))
.doAfterTerminate(() -> Log.i(TAG, "数据查询完毕!!"))
.subscribe((Object poetryList) -> {
Log.i(TAG, "doOnNext");
if (null != poetryList) {
Log.i(TAG, new Gson().toJson(poetryList));
}
},
(Throwable throwable) ->{
Log.i(TAG, "发生异常了,异常错误是: " +
throwable.getMessage());
}
);
或者
poetryTestAPI.getPoetryList(1, 10)
.compose(composeTransformer)
.doOnSubscribe(() -> Log.i(TAG, "开始加载数据!!"))
.doAfterTerminate(() -> Log.i(TAG, "加载数据完成!!"))
.subscribe(list -> {
Log.i(TAG, "doOnNext");
if (null != list) {
Log.i(TAG, new Gson().toJson(list));
}
}, throwable -> {
Log.i(TAG, "发生异常了,异常错误是: " +
throwable.getMessage());
});
运行程序,输入如下:
开始加载数据...
doOnNext
{"code":200,"message":"成功!","result":[{"authors":"宋太祖","content":"欲出未出光辣达,千山万山如火发。|须臾走向天上来,逐却残星赶却月。","title":"日诗"}, ...]}
数据查询完毕!!