浅谈Android响应式编程与Rxjava

来源:互联网 发布:淘宝店铺流量 编辑:程序博客网 时间:2024/05/30 23:38

一、响应式编程

响应式编程一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。


例如,在命令式编程环境中,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原理


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():安卓主线程

 如下subscribeOn()之前的代码运行在新线程中,而observeOn()后的代码运行在安卓主线程中。
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操作符

Map:用于链式调用中,变换当前数据类型为另一种数据类型。



FlatMap/concatMap:用于链式调用中,变换当前数据类型为另一种Observable泛型,可用于消除回调地狱。


0 0
原创粉丝点击