浅谈Android响应式编程与Rxjava

一、响应式编程

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


例如,在命令式编程环境中,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泛型,可用于消除回调地狱。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值