您现在的位置:新闻首页>热点要闻

缺少的RxJava 2指南:增强您的Android开发

2018-01-26 11:43大渝新闻网编辑:admin人气:


RxJava总是吓到许多开发者。一开始似乎非常令人难以置信,但是一旦进入凹槽,就会沉迷其中。
 
RxJava 2发布了一段时间,其中重新整理了整个图书馆。但是,如果对反应式编程的基本概念没有深入和正确的理解,那么您就不会太靠谱。
 
下面深入介绍RxJava的核心概念,并附上几个真实世界的例子,以及易于理解的代码示例,这些示例将帮助您理解基本原理。
增压徽章

Android的异步世界
也许你还没有想过,但Android的世界在很多方面是异步的。如果您需要将数据读取/写入磁盘,则必须等待一段时间,然后才能完成操作。这不可能马上发生,对吧?
 
当您进行网络调用以从远程服务器检索数据时,情况与此类似。网络通话不同步。这需要一些时间,从几毫秒到几秒,取决于您的网络质量,服务器负载等。
 
如果你再考虑一下,你会发现整个用户输入机制本质上是异步的。该设备持续等待用户输入,如触摸,拖动,轻扫,捏等,并相应地对这些输入作出反应。
 
让我们开始思考反应
事实上,Android世界中几乎所有的东西都是异步的,从数据库事务,文件操作和网络调用到繁重的计算,用户输入和推送通知。
 
那么为什么我们在以同步的方式建模我们的应用程序时如此努力呢?当他们运行的世界在本质上是非常异步的时候呢?
在开始编写应用程序之前,您不应该问自己一个问题吗?你不觉得用更好的方法可以让你的生活变得更轻松吗?
 
开始以被动的方式思考。我知道在经过一辈子的思考和写作代码之后可能会很困难。但是我们都需要从某个地方开始,对吧?
 
反应式编程并不困难。这是不同的。
反应式编程是非常强大的,但如果您知道如何正确使用它,也更容易。如果这对你来说似乎很难,那简直就意味着你还没有正确的概念。
 
它可能需要时间 - 也许很多时间 - 但一旦你得到它,你一定会爱上它的美丽和力量。
 
重点首先理解核心概念和基本面。试着想一下你可以充分利用它们的场景,当你陷入困境的时候,提醒自己,你可能需要改变你正在思考或者解决问题的方式。
 
走反应路的好处
如果您已经开始看到反应式编程能够投入到您的手中,请考虑在Android开发中引入RxJava,您将享受到的直接好处。
 
多线程就像老板
在Java中多线程可能很困难。反应式编程可以使执行复杂的线程操作,保持同步,并将结果交付给友好的UI线程变得非常简单和方便。
 
消除可怕的“回拨地狱”
当你需要执行多个异步操作,并且每个操作都依赖于前一个操作的结果时,你会不知不觉地在代码中创建  回调函数。
 
理解和维护这样的代码库变得非常困难。使用响应式编程,您可以完全消除这种情况,并编写干净,简洁和可维护的代码。
 
错误处理变得轻而易举
当您与现实世界的异步数据源(如网络,数据库,文件等)交互时,并不总是阳光和彩虹。
 
他们有时可能会失败,当他们这样做时,您需要有一个强大的错误处理机制来轻松解决各种关键的情况。
 
运营商的武库
反应式编程的真正威力来自经过充分测试和强大的操作员的庞大武库,可以帮助您轻松地执行几个常见的(而且不那么常见的)任务。库存中有很多可用的操作员,这正是大多数开发人员不知所措的地方。
 
您需要先了解一些基本的操作员,然后在需要时慢慢学习。你不需要在第一天学习所有的东西。
 
更少的代码,更少的错误,更少的错误
当您以被动方式编写代码时,代码更具可读性,可理解性和可维护性。你会写更少的代码,减少挫折,减少错误,编写更健壮和稳定的代码。
 
享受跨平台支持
反应式编程是一种可用于多种语言的编程模式,包括  Java,JavaScript,Python,Swift,Kotlin,C ++等等。
 
如果您在移动平台,网络或后台工作,则无关紧要。你获得的知识可以帮助你在任何地方编写更好的代码。
 
这些只是 采取被动方法 编写代码的一些好处。当您开始进行反应式编程时,您会发现更多。
 
我们来谈谈RxJava
以最简单的话来说, 反应式编程就是消费者对数据反应的一个范例。这是一个概念,ReactiveX是旨在提供跨多种编程语言实现这个概念的项目。
 
ReactiveX网页标题如下:
 
观察者模式正确。
ReactiveX是来自观察者模式,迭代器模式和函数式编程的最佳想法的组合。
RxJava只是Java编程语言这个概念的实现。最近,发布了一个重要更新,在Reactive Streams规范之上重写了整个库。
 
本文中我将重点放在RxJava 2  上。
 
RxJava的3 O's
RxJava的核心概念是可观察者,观察者和操作者。
 
在被动的世界里,把所有东西当成一个流。某些东西会产生/发射一些数据流,以供别的东西修改或消耗。但这实际上并不是一个新的概念。这只是实际的观察者设计模式,但却是无限强大的。
 
数据流的示例包括传感器数据更改,位置更新,UI中的触摸事件以及推送通知。
 
观测
可以观察到的东西是可观察的。它代表了您感兴趣并想要观察的数据的来源。
 
这是一个真实世界的例子。假设你参加了一个发言人是你感兴趣的人的会议。这位演讲者是一个可以观察的人,他为你制作消息流。
 
 
热与冷观察
只有当有人订阅它们时,观察者才能发射物品。例如,会议发言人不可能谈话,直到有人在房间里听。这些被称为冷观察。
 
同样,即使没有人订阅,我们也可以观察到一些观察项目。这就像一个演讲者开始向一个空荡荡的房间演示。与会者可以稍后抵达并开始聆听。这些被称为热守望者。
 
在Android世界中,一个冷观察者可以是一个网络调用,如果没有人订阅它,则不会获取(或发出)数据。观察者进行网络调用,获取数据,并且只有当有人对这个事件感兴趣并且订阅它时才发出它。这些排放不是在多个用户之间共享的。
 
另一方面,可观察的热点可以是位置更新事件流。即使没有人对他们感兴趣,位置更新仍然会继续发生。如果用户最终对这些更新表现出兴趣并考虑订阅,则它将 开始获得从其订阅点发出的更新,但是它不会影响该流。
 
 
获取,设置,编码
你通常会使用的observable的例子是这样的:
 
Observable<Movie> movieObservable = remoteService.getMovies();
在这里,observable可以发出  从某个远程数据源获取的Movie 对象。可以有单个项目,多个项目或者这个可观察项目发出的项目。如果observable无法获取数据,则会发出错误信号。
 
如果你需要创建一个observable,你可以这样做:
 
Observable<Movie> movieObservable = Observable.create(emitter -> { try { // Fetches Movie objects from the network, database, etc. List<Movie> movies = getMovies(); for (Movie movie : movies) { emitter.onNext(movie); } emitter.onComplete(); } catch (Exception e) { emitter.onError(e); } });
我们将谈谈onNext () ,在完成(),和onerror的()后面详细方法。以下是您快速创建观察值的一些便利方法:
 
Observable.just() - 围绕任何数据类型创建一个observable,并发射给定的项目。
Observable.fromArray() - 创建一个逐个发出给定数组的所有项目的observable。
Observable.interval() - 创建一个在给定时间间隔内发出一个整数序列的observable。
Observable.empty() - 创建一个不发生任何事情并成功完成的observable。
Observable.error() - 创建一个不发生任何事情并抛出错误的observable。
查看此页面  以获取可以创建可观察对象的所有方法的完整列表。
 
观察员
任何对观察者感兴趣并赞成的东西都可以称为观察者。每当源可观察者发射一些项目,所有订阅的观察者都会收到通知。
 
在我们这个人为的会议范例中,所有听取发言者的与会者都是观察员。每当演讲者说出舞台上的一些东西时,所有的与会者都可以听到并做出反应。
 
可以有一个观察者或多个观察者订阅源observable,并且只要源observable发出一些东西,他们都会得到通知。
 
观察员可以收到的主要有三类事件:
 
onNext(T)  将被调用,当源observable发射一个特定的项目(类型T)。如果源observable有多个项目发射,它将被多次调用。
当源observable完成发射其所有项目时,onCompleted () 将被调用。这是一个终端事件,在这一点之后不会有更多的事情发生。这只是表明observable已经成功完成。
onError(Throwable) 将在源observable在发射项目时遇到错误时被调用。这也是一个终端事件,在这一点之后也不会有更多的排放。这表明可观察的已经失败。它提供了一个 throwable,其中包含错误的详细信息。
 
获取,设置,编码
现在让我们看看一些真实的代码:
 
DisposableObserver<Movie> disposable = movieObservable .subscribeWith(new DisposableObserver<Movie>() { @Override public void onNext(Movie movie) { // Access your Movie object here } @Override public void onError(Throwable e) { // Show the user that an error has occurred } @Override public void onComplete() { // Show the user that the operation is complete } });
这似乎很多,但实际上很简单。 
 
我们在这里所做的是使用subscribeWith()方法来订阅电影observable。我们正在使用一个  DisposableObserver,它有三种方法用于前面讨论的三种不同的事件类型。所述onNext (动画)的方法将被称为每一个时间电影对象由观察到的获取。它可以从网络,数据库,文件或任何其他来源获取。重要的是,订阅它的观察者将始终被通知流中发生的事件。
 
因此,如果您的数据存储中有10部电影,则onNext()方法将被调用10次,包含10个  Movie 对象。操作成功后,将调用onComplete()方法,但如果操作失败,则会使用相应的错误对象调用onError()方法。
 
 
处置,但什么?
DisposableObserver不过是一个观察者,可以在实现  Disposable  接口的时候处理。每当观察者订阅一个观察者时,他们之间就形成一个连接,当不需要的时候有效地需要被清除(或终止)。否则会导致资源泄漏。
 
听众不应该永远听取事件; 它需要停止一段时间。这与在完成使用数据库游标或文件输入/输出流时需要关闭数据库游标或文件输入/输出流的场景类似,否则,这些未释放的资源会增加内存占用或导致泄漏。
 
你的观察者在完成工作之后只不过是垃圾。所以当你不需要它们的时候,你可以这样做来处理你的观测值:
 
@Override public void onDestroy() { if (disposable != null && !disposable.isDisposed()) { disposable.dispose(); } super.onDestroy(); }
您也可以使用  CompositeDisposable  来添加所有的一次性物品,并一次摆脱所有的一次就这样。
 
操作者
RxJava的真正威力来自于它所带来的巨大的运营商武器。运算符是纯粹的函数,可以转换或修改可观察的流。
 
回到我们的会议范例,假设有一个新的演讲者开始讲德语,但与会者只懂英语。
 
这就是翻译人员可以将翻译人员的每个句子翻译成有意义的东西,让所有参与者都能理解的地方。
 
让我们来谈谈一些RxJava运营商:
 
filter() - 我们可以使用此运算符来细化源observable发出的项目,并创建一个只包含符合所需条件的项目的新observable。
假设我们的可观看电影发出了许多具有不同评级(从1到5星)的电影,但是我们只想显示那些评级为5星的电影,
 
movieObservable.filter(new Predicate<Movie>() { @Override public boolean test(@NonNull Movie movie) throws Exception { return movie.getRating() == 5; } });
而强大的拉姆达 可以把它变成这样的东西:
 
movieObservable.filter(movie -> movie.getRating() == 5);
map() - 我们可以使用这个操作符将源observable发出的项目转换成完全不同的东西,并创建一个包含这些修改项目的新的observable。
假设我们要求显示的电影大纲不能超过500个字符。
 
Observable<Movie> movieObservable = getMoviesFromDatabase(); movieObservable.map(new Function<Movie, Movie>() { @Override public Movie apply(@NonNull Movie movie) throws Exception { return StringUtils.truncate(movie.getSynopsis(), 500); } });
使用lambdas和静态导入后,我们有这样的东西:
 
movieObservable.map(movie -> truncate(movie.getSynopsis(), 500));
现在我们已经创建了一个全新的电影流,其中每个包含不超过500个字符的摘要。
 
skip() - 我们可以使用这个操作符从开始源observable中跳过一些项目,并创建一个没有这些项目的新的observable。
假设我们知道我们的movie observable总是在流的开始处发出一个虚拟的Movie对象(包含一些元数据),不应该向用户显示。
 
movieObservable.skip(1);
concat() - 我们可以使用这个运算符将多个observable连在一起,而不交织它们。
假设我们有两个数据源从数据库和网络中获取电影,我们希望显示从数据库获取的电影,然后是从网络获取的电影。
 
Observable<Movie> database = getMoviesFromDatabase(); Observable<Movie> network = getMoviesFromNetwork(); Observable<Movie> resultObservable = Observable.concat(database, network);
现在我们可以订阅这个resultObservable,它有来自数据库的电影在电影从网络前发出。
 
我们已经观察到,这些运算符方法的返回类型也是可观察的,这使得我们可以将多个运算符依次链接起来并执行疯狂的事情。
 
movieObservable .skip(1) .filter(movie -> movie.getRating() == 5) .map(movie -> truncate(movie.getSynopsis(), 500));
在这个例子中,我们跳过流中发出的第一个项目,然后只筛选评级为5的电影,然后将每个电影项目的摘要截断为500个字符。所有这一切只发生在四行代码中。
 
RxJava中有数百个运营商,每个运营商都要花费超过10,000个字。阅读一篇长篇文章对你来说将是一件痛苦的事情,所以这里有一个链接到你可以使用的所有操作符的完整列表。 
 
奖金的概念
如果我没有涉及到两个重要的概念:observeOn / subscribeOn和schedulers,这篇文章将是不完整的。
 
observeOn / subscribeOn
这些就像讨论的其他操作符一样,但是这些可以用来轻松控制RxJava中的多线程。
 
subscribeOn()
使用此运算符可指定源observable将在哪个线程上发送其数据。这个操作符只能在源观察点上工作。
 
假设你的源observable应该从网络中获取数据。显然,这个操作必须在后台线程中执行,因为Android不允许在主线程上进行网络操作。
 
这是subscribeOn运营商发挥作用的地方。您只能使用这个操作符一次。如果多次使用它,只有最接近源的定义才会生效。
 
movieObservable .subscribeOn(Schedulers.io()) .subscribe(movie -> { // Use your movie item here }, throwable -> { // Handle the error here });
这将使电影observable在I / O线程上运行。现在看到另一个变种:
 
movieObservable .subscribeOn(Schedulers.computation()) .subscribeOn(Schedulers.io()) .subscribe(movie -> { // Use your movie item here }, throwable -> { // Handle error here });
您可能会认为第二个subscribeOn()(与Schedulers.io())将发挥作用。但是只有最接近源的subscribeOn ()才会发挥其魔力,而不是其他任何东西。
 
observeOn()
您可以使用此运算符来指定观察者将在哪个线程上观察排放。
 
假设您的源observable在I / O线程上发射项目。在Android中,为了在UI中显示某些内容,您必须仅在Android主线程上使用数据。所以这就是  observeOn ()发挥作用的地方。
 
movieObservable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(movie -> { // Use your movie item here }, throwable -> { // Handle error here });
现在,您将能够在UI中访问和显示您的电影项目,因为它们都在UI线程中被观察到。但是在前面的例子中,由于没有使用 observeOn(),所有的项目都在I / O线程中被发射和观测。
 
与subscribeOn ()不同  , 我们可以多次使用observeOn()进行无缝线程切换。
 
movieObservable .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .flatMap(movie -> truncate(movie.getSynopsis(), 500)) .observeOn(Schedulers.io()) .filter(movie -> isInDatabase(movie)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(movie -> { // Use your movie item here }, throwable -> { // Handle error here });
这是一个人为的例子,让你明白你如何在真实场景中使用它。我已经使用observeOn()三次。源observable在I / O线程上发射项,然后切换到计算线程来执行截断操作(让我们假设它需要复杂的计算)。
 
                                              RxJava中的大理石图
之后,我再次切换到I / O线程来执行过滤操作,我只需要那些已经存在于数据库中的项目。现在,我将线程最后一次切换到主线程,以便刚才指定的观察者能够观察和使用Android主线程上的项目。
 
所以,在七行代码中,我做了很多的多线程,如果我们必须用传统的方式来做,这将花费大量的时间和精力。
 
调度程序
因为在前面的一些例子中你已经看到了一些调度器,可能会想知道这些是什么。
 
调度程序表示要执行的操作的特定线程。
 
RxJava中有几个调度程序,其中包括:
 
Scheduler.io() - 用于在I / O线程上执行的操作,例如网络调用,数据库事务,文件访问等。
Scheduler.computation() - 对于计算量大且需要在为此目的而优化的线程上执行的操作,例如解析数百万个电话号码的大数据集。
Scheduler.newThread() - 用于在全新线程上执行的操作。您应该限制自己始终创建新线程,并使用其他可用调度程序,以便框架可以使用线程池等技术改进线程性能。
Scheduler.immediate() - 用于测试和调试目的,您可以在当前线程本身而不是在单独的线程上执行操作。
AndroidSchedulers.mainThread() - 用于在Android主线程上执行的操作,例如在UI上显示数据。不过,您需要使用RxAndroid库。
 
 
现在去尝试一下
现在,您应该对反应式编程背后的概念有一个很好的把握,以及如何开始使用RxJava 2来增强您的Android开发。
 
如果你脑子里还有什么东西还不清楚的话,可以考虑再读这篇文章。 围绕着可观察的,观察者,操作者和调度者的基本概念应该在你的头脑中清晰地表达出来,在你的应用中正确使用RxJava。
 
此外,尝试启动您的IDE,并开始玩API。只有这样,你才能牢牢把握这个非常强大的工具。一旦你爱上它,就不会有回头。

(来源:未知)

织梦二维码生成器
已推荐
0
  • 凡本网注明"来源:大渝新闻网的所有作品,版权均属于中大渝新闻网,转载请必须注明中大渝新闻网,http://www.aaduna.com/。违反者本网将追究相关法律责任。
  • 本网转载并注明自其它来源的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品来源,并自负版权等法律责任。
  • 如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。




  • 推荐专题上方


图说新闻

更多>>
Skyrmions打开了进入下一级数据存储的大门

Skyrmions打开了进入下一级数据存储的大门


返回首页