写点什么

一篇不太一样的 RxJava 介绍,2021 年 Android 开发者跳槽指南

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

fun getList() : List<MetaData>


fun getBitmap(metaData : MetaData) : Bitmap}


很多同学喜欢 RxJava 都是因为链式调用看起来非常舒服,而链式调用或者说高阶函数或者操作符并不是 RxJava 的专利,Java8 的 Stream API 和 Kotlin 都有相关的操作,比如我们的代码在 kotlin 中可以这样调用


model.getList().map { model.getBitmap(it) }.forEach { showBitMap(it) }


是不是看起来和你们所谓的优雅简洁的 RxJava 链式调用一样呢?


但是同步意味着阻塞,而网络加载 Bitmap 大家都知道是非常耗时的。为了不阻塞用户界面(UI 线程),我们希望他在后台异步执行,执行后再输出到前台。 所以我们 Android 中最简单直接的方法就是加入 CallBack,来实现异步通信。我们的代码就变成这样


//定义 CallBackinterface CallBack<T> {fun onSuccess(t:T)


fun onError(error:Error)}


interface Model{fun getList(callback:CallBack<List<MetaData>>)


fun getBitmap(metaData:MetaData, callback:Callback<MetaData>)}


看过很多 RxJava 教程的同学肯定觉得这里我要讲 Callback Hell(回调地狱)了,然后开始展示代码 RxJava 来解决回调地狱的问题,但如果这样我这篇文章也没什么意义了,岂不是和很多入门文章都一样了?


我们先来看看为什么我们会出现回调地狱?而在同步的时候却可以保持我们喜欢的**“链式调用”** 我们在同步的时候,我们做的事情可以简化成这样: 进入主界面 -> 通过 getList 方法获取 List -> 根据 list 逐一操作获取 bitmap -> 显示 bitmap 可以看到,我们确实是一条链,所以很简单的通过 stream api 来实现**“链式调用”**。


但是异步的时候呢? 进入主界面 -> getList(callback:CallBack<List>)方法将我们的 CallBack 传给后台 -> 等待后台回调我们的 CallBack


重点来了,与同步的不同,我们这里不是直接获得了我们的 List。而是在等待着异步的另一方通知我们。 同步的时候,我们直接拉取数据 :



而异步的时候,直观的看我们应该是在“等待”数据,异步对象向我们推送数据。




所以在我们的角度,我们是被动的,也就是英语中的 reactive ,也就是所谓的响应式


我们回到我们的例子:


同步的时候,我们是这样的


interface Model{fun getList() : List<MetaData>


fun getBitmap(metaData : MetaData) : Bitmap}


而异步的时候,我们的方法没有了返回值,多了个参数,所以不能使用漂亮的**“链式调用”。 这是因为 List 本身,就是一种同步的类型。我们每次操作 List,都是对 List 来拉取**数据。不信?我们来看下:


大家都知道 List 并不是最基础的集合,常用的集合还有 HashMap,Set,Table,Vector 等等等等。他们都有一个共同的父类: Iterable


interface Iterable<out T> {fun iterator(): Iterator<T>}


这里的 iterator 就是迭代器,他是这个样子的


interface Iterator<out T> {


fun next(): T


fun hasNext(): Boolean}


使用的时候也就是我们最麻烦的迭代方式:


val i = iterator()while(i.hasNext()){val value = i.next()}


所以我们在 Java 中有了 foreach,以及后面的 stream api 等等语法糖。 这里我们看到了,我们每次确实首先询问 List,有没有值,如果有我们获取这个值,如果没有,跳出循环,对 List 的操作结束。读取完毕。


想象一下,如果我们有一种 AsyncList,对他的读取都是AsyncList来通知我们,然后再和同步的时候一样使用高阶函数比如 map/foreach 等等该多好。比如


interface Model{fun getList() : AsyncList<MetaData>


fun getBitmap(metaData : MetaData) : Bitmap}


我们就可以像同步一样,


model.getList().map { model.getBitmap(i


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


t) }.forEach { showBitMap(it) }


现在我们来根据Iterable设计我们的 AsyncList,上面我们知道了Iterable是同步的,是拉取数据,我们需要的AsyncList是异步的,是他推送数据给我们。 我们和List一样,给所有的异步集合来一个父类,来设计一个AsyncIterable,我们知道Iterable提供Iterator通过我们主动询问Iteratornext,hasNext等方法我们主动拉取数据。 所以我们的AsyncIterable理论上来说,应该是我们通过注册AsyncIterator的方式,将我们的AsyncIterator传递给AsyncIterable,让他来通知我们,实现异步和推送数据。 所以我们的AsyncIterable的实现应该是这样的


interface AsyncIterable<T> {fun iterator(iterator : AsyncIterator<T>)}


(看起来好像有点眼熟?)


我们再来设计AsyncIterator,同步的方式两个方法,一个是 hasNext,也就是我们主动询问 iterable 接下来之后还有没有值的过程,如果是异步的方式,这应该是我们的AsyncIterable,来通知我们,他接下来以后还有没有值。 所以变成了这样:


fun hasNext(has : Boolean)


对的,通过这种类似 CallBack 的方式,通知我们有没有值。true 就是还有值,一旦接收到 false,就代表迭代结束,我们的AsyncIterable已经遍历完成了。 另一个方法 next() 就是我们来主动询问,当前的值是什么。所以我们的AsyncIterable就是通过这个方法,来通知我们当前的值是什么,依然还是通过类似 CallBack 的方式:


fun onNext(current:T)


(是不是有些眼熟?(手动滑稽))


这里有两个问题: 第一个问题:我们在这里隐藏了一个错误,因为 hasNext()方法返回 false 的时候不一定是没有接下来的值了,也有可能是处理当前值的时候出现了某些个错误或者异常,这样他就不能处理接下来的值,这时候我们的 app 就会崩溃。所以在异步的时候,我们希望我们的AsyncIterable在出错的时候,可以通知我们他出错了,我们也就不进行接下来的处理了。所以我们有了:

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
一篇不太一样的RxJava介绍,2021年Android开发者跳槽指南