一、响应式编程
响应式编程一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
例如,在命令式编程环境中,a:=b+c表示将表达式的结果赋给a,而之后改变b或c的值不会影响a。但在响应式编程中,a的值会随着b或c的更新而更新。
电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化 。
另一个例子是硬件描述语言,比如Verilog,这里响应式编程可以对电路中传播的信号变化进行建模。
二、RxJava与RxAndroid的使用
参见两个项目的GitHub首页:
https://github.com/ReactiveX/RxJava
https://github.com/ReactiveX/RxAndroid
三、Rxjava
什么是Rxjava?按照Rxjava在GitHub首页上的介绍:RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
一个在 JVM 上使用的可观测的序列来组成异步的、基于事件的程序的库,三个关键字:可观测序列、异步、基于事件。
即可以使用链式调用来完成异步操作,底层基于事件传递机制。
为什么要使用RxJava?逻辑更清晰,代码更简洁(配合lambda表达式),能够消除回调地狱。
以消除回调地狱为例:
//The "Nested Callbacks" Way
public void fetchUserDetails() {
//first, request the users...
mService.requestUsers(new Callback<GithubUsersResponse>() {
@Override
public void success(final GithubUsersResponse githubUsersResponse,
final Response response) {
Timber.i(TAG, "Request Users request completed");
final synchronized List<GithubUserDetail> githubUserDetails = new ArrayList<GithubUserDetail>();
//next, loop over each item in the response
for (GithubUserDetail githubUserDetail : githubUsersResponse) {
//request a detail object for that user
mService.requestUserDetails(githubUserDetail.mLogin,
new Callback<GithubUserDetail>() {
@Override
public void success(GithubUserDetail githubUserDetail,
Response response) {
Log.i("User Detail request completed for user : " + githubUserDetail.mLogin);
githubUserDetails.add(githubUserDetail);
if (githubUserDetails.size() == githubUsersResponse.mGithubUsers.size()) {
//we've downloaded'em all - notify all who are interested!
mBus.post(new UserDetailsLoadedCompleteEvent(githubUserDetails));
}
}
@Override
public void failure(RetrofitError error) {
Log.e(TAG, "Request User Detail Failed!!!!", error);
}
});
}
}
@Override
public void failure(RetrofitError error) {
Log.e(TAG, "Request User Failed!!!!", error);
}
});
}
上面代码很好理解,第一次网络交互成功后发起第二次网络交互,即第一层网络交互成功后又嵌套了第二层网络交互,层层嵌套的话就发生了“回调地狱”。
使用RxJava修改后的版本:
public void rxFetchUserDetails() {
//request the users
mService.rxRequestUsers().concatMap(Observable::from)
.concatMap((GithubUser githubUser) ->
//request the details for each user
mService.rxRequestUserDetails(githubUser.mLogin)
)
.toList()
//define which threads information will be passed on
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
//post them on an eventbus
.subscribe(githubUserDetails -> {
EventBus.getDefault().post(new UserDetailsLoadedCompleteEvent(githubUserDetails));
});
}
直观的看,就是代码变成链式调用了,并且没有层层嵌套,消除了回调地狱。
RxJava原理
基于扩展的观察者模式,具体请看如下链接,有专门介绍RxJava原理:
RxJava异步实现
关键词:subscribeOn()、observeOn()与Scheduler
。
Scheduler 表示不同的线程。
下面是可能会用到Scheduler:
-
Schedulers.computation():用于计算型工作例如事件循环和回调处理,不要在I/O中使用这个函数(应该使用Schedulers.io()函数);
-
Schedulers.from(executor):使用指定的Executor作为Scheduler;
-
Schedulers.immediate():在当前线程中立即开始执行任务;
-
Schedulers.io():用于I/O密集型工作例如阻塞I/O的异步操作,这个调度器由一个会随需增长的线程池支持;对于一般的计算工作,使用Schedulers.computation();
-
Schedulers.newThread():为每个工作单元创建一个新的线程;
-
Schedulers.test():用于测试目的,支持单元测试的高级事件;
-
Schedulers.trampoline():在当前线程中的工作放入队列中排队,并依次操作。
-
AndroidSchedulers.mainThread():安卓主线程
public void rxFetchUserDetails() {
//request the users
mService.rxRequestUsers().concatMap(Observable::from)
.concatMap((GithubUser githubUser) ->
//request the details for each user
mService.rxRequestUserDetails(githubUser.mLogin)
)
.toList()
//define which threads information will be passed on
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
//post them on an eventbus
.subscribe(githubUserDetails -> {
EventBus.getDefault().post(new UserDetailsLoadedCompleteEvent(githubUserDetails));
});
}
Rxjava线程间自由切换
observeOn()
指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求,只要在每个想要切换线程的位置调用一次 observeOn()
即可。不过,不同于 observeOn()
, subscribeOn()
的位置放在哪里都可以,但它是只能调用一次的。
如下图:
RxJava操作符