设为首页 加入收藏

TOP

在Andoid中如何使用RxJava 2进行多线程编程?(一)
2018-01-01 06:07:03 】 浏览:521
Tags:Andoid 如何 使用 RxJava 进行 线程 编程

如果你还没有接触RxJava或者刚刚开始使用它的话,那么你会发现始终会有很多新东西要学习。我们在GO-JEK的App中需要执行很多的异步操作,而且我们无法在UI的速度和流畅性上妥协


在本文中,我们将会讨论如何使用RxJava真正的多线程功能,它会让复杂的App开发过程再次变得简单、容易和有趣。本文中的所有代码样例都会关注RxJava,但是文中讨论的概念同样适用于其他的反应式扩展(Reactive Extension)


任何一篇关于RxJava的文章都会包含一个“为什么要进行反应式编程”的章节,我们也不打算破坏这个约定。在Android中采用反应式的方式构建App会带来多项收益,接下来我们讨论几项你真正值得关注的好处。


如果你已经做过一段时间的Android开发的话,你肯定会明白嵌套回调会快速地让所有事情失去控制。


如果你想按顺序执行一系列的异步操作并且下一步操作的行为要依赖于上一步操作的结果,那么你就会遇到这种状况。几乎瞬间,代码就会变得超级丑陋和难以管理。


在命令编程的世界中,如果你要执行大量复杂、异步的操作,错误可能会在任意的地方出现,为了处理这些场景,我们就需要将大量补丁式的代码到处放得到处都是,从而形成大量重复和繁琐的代码。


我们都知道(私下也承认)在Java中编写多线程代码有多困难。在后台线程中执行一段代码并在UI线程中获取结果,这听起来似乎很简单,但实际上有很多复杂的情况需要处理。


通过使用RxJava,你可以非常容易地在任意线程中执行复杂的操作,它会维持适当的状态同步,并能够让你无缝地切换线程。


RxJava所带来的好处是无穷无尽的,就此可以谈论几个小时,但是现在我们要更深入地探索一下它为多线程编程所带来的真正威力。


是的,你没有看错。RxJava默认情况下跟多线程一点关系都没有。在官方网站上,RxJava是这样定义的:


看到“异步”这个词,很多人就形成了一种误解,认为RxJava默认就是多线程的。的确,它支持多线程并且提供了一些强大的特性以便于我们执行异步操作,但是不能就此断定它的默认行为就是多线程的。


如果你多少了解一些RxJava的话,会知道它的基本构造为:


如果你运行上面的代码片段的话,你会发现所有的执行过程都在应用的主线程中执行(请关注打印出来的日志中的线程名)。这表明在默认情况下,RxJava是阻塞的。所有的过程都是在代码运行所在的线程上执行的。


额外的福利:想知道doOnNext()是什么吗?它只是一个副作用操作符,能够让你从observable链中脱离出来并执行一些不那么纯的操作,你可以阅读本文了解更多的信息。


如果我们想要在Android中使用RxJava做一些基本的多线程操作,需要做的就是熟悉SchedulersobserveOn/subscribeOn 操作符,这样的话,就可以开始了。


现在,看一个最简单的多线程用例。假设,我们想要通过网络获取一个Book列表,并且要在应用的UI线程中展现这个列表,我们就采用这个简单直接的用例作为开始。


在这里,有一个getBooks()方法,它会发起网络调用并获取图书列表。网络调用会耗费一定的时间(通常几毫秒到几秒钟的时间),因此,我们使用subscribeOn()并指定Schedulers.io() Scheduler在I/O线程中执行操作。


我们同时还使用了observeOn()操作符和AndroidSchedulers.mainThread() Scheduler,以便于在主线程中消费结果并将图书列表填充到应用的UI之中。这些知识可能你之前已经了解过或使用过了。


不必担心,我们马上就会进入更高级的内容。现在展现的这些内容只是为了确保我们在同一个起跑线上,在深入介绍更深入内容之前能有一个基本的认识。


RxJava中的多线程操作主要是由强大的Scheduler集合提供的。在RxJava中,我们无法直接访问或操作线程。如果想要使用线程的话,必须要通过内置的Scheduler来实现。


你可以将Scheduler视为线程或线程池(一个线程的集合),能够执行不同类型的工作


简而言之,如果你需要在特定的线程中执行任务的话,我们就需要此选择恰当的Scheduler,Scheduler接下来会从它的池中获取一个可用的线程,并基于该线程执行任务。


在RxJava框架中有多种类型的Scheduler,但是这里比较有技巧的一点就是为合适的工作选择恰当的Scheduler。如果你没有选择恰当的Scheduler的话,那么任务就无法最优地运行,所以接下来,我们尝试理解每一个Scheduler。


这是由无边界线程池作为支撑的一个Scheduler,它适用于非CPU密集的I/O工作,比如访问文件系统、执行网络调用、访问数据库等等。这个Scheduler是没有限制的,它的线程池可以按需一直增长。


这个Scheduler用于执行CPU密集的工作,比如处理大规模的数据集、图像处理等等。它由一个有界的线程池作为支撑,线程的最大数量就是可用的处理器数量。


因为这个Scheduler只适用于CPU密集的任务,我们希望限制线程的数量,这样的话,它们不会彼此抢占CPU时间或出现线程饿死的现象。


这个Scheduler 每次都会创建一个全新的线程来完成一组工作。它不会从任何线程池中受益,线程的创建和销毁都是很昂贵的,所以你需要非常小心,不要衍生出太多的线程,导致服务器系统变慢或出现内存溢出的错误。


理想情况下,你应该很少使用这个Scheduler,它大多用于在一个完全分离的线程中开始一项长时间运行、隔离的一组任务。


这个Scheduler是RxJava 2新引入的,它的背后只有一个线程作为支撑,只能按照有序的方式执行任务。如果你有一组后台任务要在App的不同地方执行,但是同时只能承受一个任务执行的话,那么这个Scheduler就可以派上用场了。


我们可以使用它创建自定义的Scheduler,它是由我们自己的Executor作为支撑的。在有些场景下,我们希望创建自定义的Scheduler为App执行特定的任务,这些任务可能需要自定义的线程逻辑。


假设,我们想要限制App中并行网络请求的数量,那么我们就可以创建一个自定义的Scheduler,使其具有一个固定线程池大小的Executor:Scheduler.from(Executors.newFixedThreadPool(n)),然后将其应用到代码中所有网络相关的Observable上。


这是一个特殊的Scheduler,它无法在核心RxJava库中使用,要使用它,必须要借助RxAndroid扩展库。这个Scheduler对Android App特别有用,它能够在应用的主线程中执行基于UI的任务


默认情况下,它会在应用主线程关联的looper中进行任务排队,但是它有一个其他的变种,允许我们以API的形式使用任意的Looper:AndroidSchedulers.from(Looper looper)


注意:在使用无边界线程池支撑的Scheduler时,比如Schedulers.io(),我们要特别小心,因为它有可能会导致线程池无限增长,使系统中出现大量的线程。


现在,我们对不同类型的Scheduler已经有了一个清晰的理解,并且掌握了何时该使用哪种Scheduler,我们继续前进,接

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java集合:整体结构 下一篇Java集合类:AbstractCollection..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目