0°

RxJava实战技巧大全

文章内容大纲 (右击展开→→)

内容预览:
  • 所谓的RxBinding是用来为界面元素绑定事件的,比如为Buttong设置点击事件等~
  • 可以说,引入RxJava,就放弃古老而沉重的AsyncTask吧(初学者还是要学As...~
  • Schedulers.computation():同样采用了线程池机制,只不过线程池中线程...~

始发于微信公众号: 程序员小乐

RxJava实战技巧大全

分享互联网、技术、情感等干货平台。您还可以向公众号投稿,将自己总结的技术、心得、经验分享给大家。学无止境,不求尽如人意,但求问心无愧。让学习成为一种美、一种习惯。值得爱学习的你去关注,感觉有帮助转发分享让更多的人去关注!点击上方蓝字关注!

作者: 江湖人称小白哥(已获得原创首发)
链接: http://blog.csdn.net/dd864140130/article/details/52714272(点击阅读原文即可前往) 

这几天一直看《激荡三十年》,感觉非常不错。这篇文章本身并不想写,总觉得没什么含量,后面写着写着,发现其中的有些点还是非常有意思的,因此这篇文章的重点在rxjava使用场景说明及rxjava内存优化上。rxjava的使用场景更多的取决于我们所面临的业务以及当前rxjava的一些操作符是否提供了对业务的支持,而对于内存优化上,则是要求我们尽可能快的解除订阅关系。

另外本文对RxBinding,RxLifecycle的介绍并未做过多的深入,原因在于这两个库无论是从实现还是从使用角度来说都是比较简单的,我们完全可以自行书写类似的库。

话不多说,步入正题。

引入RxBinding

在引入RxBinding之前首先要弄明吧RxBinding是什么?。

所谓的RxBinding是用来为界面元素绑定事件的,比如为Buttong设置点击事件等。浏览其源码,不难发现其实现原理也是通过包装原有事件实现的。

为什么要引入RxBinding?使用RxJava一定要引入RxBinding么?

首先很确定的说使用RxJava不要求你一定要使用RxBinding,大部分情况下没必要用。这里之所以要谈RxBinding一方面是完善我们的知识体系,看看响应式编程的思想是如何应用在Android界面元素上,另一方面是看看RxBinding能够有效的解决什么问题?

RxBinding提供了和RxJava一致的api体验,更重要的是它更好的符合RxJava做法:通过将事件转化为Observable对象,最终可以利用RxJava一系列操作符对其处理,最典型的使用场景是界面防抖动,这点我们在rxjava真实应用场景中做详细的介绍。

关于如何使用RxBinding,直接参见RxBinding项目说明即可:https://github.com/JakeWharton/RxBinding。

rxjava真实应用场景

在上一篇文章中为解决异常问题,我们引入了rxjava的支持。接下来我们来看看rxjava在实际工程中的显著应用。

场景零:线程切换

rxjava引入让使得线程切换更加的容易,几行代码就可以搞定。RxAnroid的引入更是让我们非常容易的能够切换到UI线程。可以说,引入RxJava,就放弃古老而沉重的AsyncTask吧(初学者还是要学AsyncTask的)。最典型的就是从网络中获取数据,然后在更新界面,很显然获取数据操作需要发生在子线程,更新UI操作发声明在主线程。这里我们以模拟从数据库中获取联系人操作为例:

RxJava实战技巧大全

场景一:接口依赖(flatmap)

目前大部分服务端接口设计都是通过用户名和密码登录获取access token,后面其他api的请求都是借助该token。对于需要注册功能的产品来说,我们经常面对这样的问题:使用用户名和密码登录成功后,保存服务器返回的access token,再调用服务端接口获取用户的详情信息。不难发现,这里获取用户详情的请求依赖登录请求.我们先来看传统方法是如何解决这问题:

RxJava实战技巧大全

开始时,我们大部分人会写出类似以上的代码。当然,这实现了我们想要的逻辑,但当你仔细思考的时候,会发现几个问题:

  1. 回调嵌套看起来令人疑惑。由于我们在大多数情况下是线性思维,那么此时当你看到onNext(Result<Token> tokenResult)中又去嵌套处理获取用户信息的接口你的思维不得不跳跃一下。

  2. 登录功能的异常处理点被分隔了,使我们不得不写出冗余的代码。

  3. 多次线程开销好像可以被进一步优化。

实际上这三个问题的根本原因在于我们在实现登录功能的时候是以方法作为最小单位,而不是以登录逻辑为最小单位,因此看起不是那么的连贯。现在来看看我们应该怎么样让上面的代码具有连贯性:

RxJava实战技巧大全

RxJava实战技巧大全

通过flatmap操作符,不但解决了接口依赖问题,而且使得代码逻辑相比之前更具有连贯性。另外,这里引入的BaseSubscriber在我们Retrofit响应数据及异常处理策略做过说明了,不明白的同学可以自行查阅。

场景二:接口合并(merge)

很多情况下,一个界面中需要的数据来自多个数据源(请求),而只有当所有的请求的响应数据都拿到之后才能渲染界面。

接口结果同类型

当前数据源来自多个渠道,拿到的结果属于同一类型的,比如有些数据需要从本地数据读取,而另一些数据则从网络中获取,但无论哪个数据源今最后返回的数据类型是一样的,比如:

RxJava实战技巧大全

上面的两个方法分别从磁盘和网络中获取数据,且最后的数据类型都是ArrayList<String>,现在我们来合并这两个接口:

RxJava实战技巧大全

接口结果不同类型

有些情况下,不同数据源返回的结果类型不一致,那该如何解决呢?比如当前存在两个接口:

RxJava实战技巧大全

只有当这两个请求都完成后才能更新UI,那我们该怎么做呢?同样还是使用merge操作符,关键在于如何区分响应:

RxJava实战技巧大全

场景三:构建多级缓存(concat)

缓存机制想必是众所周知。这里我们就以常见的三级缓存机制为例:首先从内存中获取数据,如果内存中不存在,则从硬盘中获取数据,如果硬盘中不存在数据,则从网络中获取数据。现在看看RxJava是如何帮我们解决这个问题:

RxJava实战技巧大全

RxJava实战技巧大全

RxJava实战技巧大全

rxjava为我们提供的concat操作符可以很容的的实现多级缓存机制。这里需要记住在getData()方法中不要忘记使用takeFirst()。concat操作符接受多个Observable,并按其顺序串联, 
在订阅的时候会返回所有Observable的数据(按顺序依次返回)。换言之,如果在getData()中不实用takeFirst(),将会并行的从内存,硬盘及网络中检索数据,这显然不是我们想要的。takeFirst操作符可以从返回的数据中取出第一个,并中断数据检索的过程。我们知道,检索速度:内存>硬盘>网络,这就意味着当我们从内存中获取到数据的时候就不会再从硬盘中获取数据,反之,则从硬盘中获取数据;当我们从硬盘中获取到数据的时候就不会再从网络中获取到数据了,反之,则从网络中获取。

这样就实现了我们的最终目标。

场景四:定时任务(timer)

在一些情况下我们需要执行定时任务,传统的做法上有两种方式可选择:Timer和SchelchExector。但是在引入rxjava之后,我们有了第三种选择:

RxJava实战技巧大全

场景五:周期任务(interval)

当然rxjava通过interval提供了周期任务的支持:

RxJava实战技巧大全

场景六:数据过滤(filter)

在处理集合时,我们经常需要过滤操作,这时候使用filte操作符就非常有用,用个简单示例:

RxJava实战技巧大全

场景七:界面防抖动(throttleFirst)

所谓的界面防抖动就是用于处理快速点击某控件导致重复打开界面的操作,比如点击某个button可以打开一个Activity,正常情况下,我们一旦点击了该Button便会等待该Activity。在应用响应比较慢,用户以为无响应而多次点击Button或者恶意快速点击的情况下,会重复打开同一个Activity,当用户想要退出该Activity的时候体验会非常差。

通过rxjava提供的throttleFirst操作符我们能够很容易防止按钮在单位时间内被重复点击的问题:

RxJava实战技巧大全

场景八:老接口适配(just)

当你在为老项目添加rxjava支持的时候,难免需要将一些方法返回类型转为Observable.通过just操作符不需要对原方法进行任何修改便可实现:

RxJava实战技巧大全

场景十:响应式界面

界面元素更新

在信息填充界面时,我们经常会遇到只有填写完必要的信息之后,提交按钮才能被点击的情况。比如在登录界面时,只有我们填写完用户名和密码之后,登录按钮才能被点击。通过借助rxjava提供的combineLatest操作符我们可以容易的实现这种响应式界面

RxJava实战技巧大全

RxJava内存优化

内存优化

借助rxjava提供的线程调度器Scheduler我们可以很容的实现线程切换,目前Scheduler提供了一下几种调度策略:

  • Schedulers.immediate():默认的调度策略,不指定线程,也就是运行在当前线程

  • Schedulers。newThread():运行在一个新创建的线程当中,相当于new Thread()操作。

  • Schedulers.io():采用了线程池机制,内部维护了一个不限制线程数量的线程池,用于IO密集型操作。

  • Schedulers.computation():同样采用了线程池机制,只不过线程池中线程的数量取决与CPU的核数,以便实现最大性能。通常用于CPU密集型操作,比如图形处理。

通过上面的介绍,我们基本能做出以下使用规则:对于网络请求及读写大量本地数据等操作,既可以采用Schedulers.newThread()也可以采用Schedulers.io(),但是优先采用Schedulers.io(),对于计算量比较大的,当然是采用Schedulers.computation()。 
这样,我们既能达到较好的性能,又尽可能的减少内存占用。

内存泄漏

尽管rxjava非常简单易用,但是随着订阅的增多内存开销也会随之增大,尤其是在配合使用网络请求的时候,稍不注意就容易造成内存泄漏。早期我也犯过多次这种错误。

当我们不需要的时候,主动取消订阅。比如在下面的代码中,我们开启一个周期任务用来不断的输出信息,那么我们需要在该Activity被销毁的时候调用mSubscription.unsubscribe()来主动的解除订阅关系防止内存泄漏。

RxJava实战技巧大全

RxJava实战技巧大全

看完上面简单的示例,想必你也明白rxjava所造成的内存泄漏往往和组件的生命周期相关。也就是我们要重点关注那些在在组件销毁之后,订阅关系却仍然存在的情况。大部分情况下,当我们的视图销毁之后,订阅关系就没有必要存在了,所以需要我们主动取消订阅即可。

存在一种特殊情况:当我们进入某个界面后,往往会发出网络请求,在返回数据后首先需要缓存数据,然后在更新界面视图。这种情况下当然不能在视图销毁后立刻解除订阅关系。那么这里需要注意的是更新UI之前需要自行判断当前视图是否存在,存在则更新,不存在就没有必要更新了。

在我们的工程中,往往存在很多个视图(Activity,Fragment等),如果在每个视图当中都要手动的解除订阅关系是件很繁琐的事情。这里有两种方式:一是在基类当中,比如BaseActivity,BaseFragment中统一取消订阅,另外一种方式就是使用RxLifeCycle这个库。

补充:RxJava中也提供了CompositeSubscription用来批量的管理订阅关系,其内部通过Set<Subscription>实现,在需要取消多个订阅关系的时候使用它也是非常方便

使用RxLifecycle

RxLifeCycle可以帮助我们在组件生命周期的某个阶段或者指定事件发生时自动取消订阅,其项目地址在:https://github.com/trello/RxLifecycle,如果你不介意引入新的库,建议使用。

compile 'com.trello:rxlifecycle:0.3.1'
compile 'com.trello:rxlifecycle-components:0.3.1'

RxLifeCycle主要提供了两个方法bindToLifecycle()和bindUntilEvent(),分别用来绑定生命周期和事件。

绑定生命周期(bindToLifecycle())

绑定生命周期的做法本质上是通过监听组件(Activity,Fragment)生命周期的变化来自动解除订阅关系。用法如下:

RxJava实战技巧大全

RxJava实战技巧大全

绑定生命周期的方式适应于在一开始就能够确定开始点,即能明确的知道订阅关系发生在哪个阶段(onCreate()?onResume(),onStart()),这样才能在恰当的方式解除订阅关系。比如在onResume()中联网获取用户数据,那么需要在onPause()中解除。

绑定事件(bindUntilEvent())

RxLifecycle中将组件生命周期的各个阶段转化为相对应的事件,因此绑定事件的方式和绑定生命周期的方式并无太大区别。和使用bindToLifecycle()不一样的是,绑定事件的方式只关心何时解除订阅关系。因为在很多情况下,我们所做的操作并不一定是在onResume()开始,在onPause()结束,此时显然不能用绑定生命周期的方法。来看看绑定事件如何使用:

RxJava实战技巧大全

RxJava实战技巧大全

总结

这里介绍了有关rxjava一些实际应用场景。尽管rxjava看起来非常容易 使用,但其内存使用问题需要我们重点关注。

本文编号1711,以后查看这片文章直接在公众号发送1711RxJava即可。

如果您觉得不错,请别忘了分享到您的朋友圈让更多的人看到!! 您的举手之劳,就是对我最好的支持,非常感谢!

推荐文章(关注公众号查看往期文章):
学习资料(干货汇集)不断更新【更新于2017-2-25】
2017 年初、阿里、腾讯、百度、华为、京东、搜狗和滴滴面试题汇集(更新篇)
如果你喜欢上了一个程序员小伙,献给所有的程序员女友
【QQ技术群】279126311 [满]
【QQ技术群】484572225 [未]

大家可以加群和大牛们一起学习,由于“大牛聚集之地”已满
可以进大牛聚集之地2群,群二维码如下:

RxJava实战技巧大全

如果人满了,可以加我的微信,我拉你进二群,我的微信:1733563441(请备注)
看完本文有收获?请转发分享给更多人
关注「杨守乐」,提升编程技能

RxJava实战技巧大全

如何关注:

① 长按二维码,选择“识别图中二维码”进行关注。

 点击微信右上角的“+”,会出现“添加朋友”,进入“公众号”,输入公众号的ysle_0313(杨守乐)名字,即可找到。

如果你有好的文章想和大家分享,欢迎投稿,直接向我投递文章链接即可。投稿邮箱:[email protected]/[email protected]
欢迎扫描关注我们的微信公众号ysle_0313,不要错过每一篇干货~

赞助方式如下链接:

http://blog.csdn.net/xiaole0313/article/details/52333666

版权声明:【我们尊重原创。此篇干货,版权属于原作者。部分文章推送时因种种原因未能与原作者联系上,若涉及版权问题,敬请原作者联系我们,立即处理。】



以上就是:RxJava实战技巧大全 的全部内容。

本站部分内容来源于互联网和用户投稿,如有侵权请联系我们删除,谢谢。
Email:[email protected]


0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论