RxJava 2.x:我应该使用Flowable还是Single/Completable?

42

我正在使用Clean Architecture开发一个Android应用程序,并将其迁移到RxJava 2.x。我需要向soap服务发送一些网络请求,因此我在domain模块中定义了api接口:

public interface SiginterApi {
    Observable<User> login(String user, String password);
    ...
    Observable<List<Campaign>> getCampaigns(List<Long> campaignIds);
}

我已经阅读过,网络请求应该使用"Flowable",因为它是一个“冷可观测对象”,可以管理背压。另一方面,我知道请求的结果将是成功(带有响应)还是错误,因此我不知道是否应该使用FlowableSingle或者甚至是Observable

此外,我的数据库访问方式如下:

public interface UserRepository extends Repository {
    Observable<Void> saveUser(String username, String hashedPassword, boolean logged, User user);
    ...
    Observable<User> findUser(String username, String hashedPassword);
}

我不知道在saveUser方法中应该使用 Completable/Flowable/Observable还是在findUser方法中应该使用Single/Flowable/Observable

6个回答

39

当一个源Observable发出数据比Subscriber消费它们的速度更快,就会产生Backpressure。这通常是与热的可观察对象相关,而不是像您的网络请求那样的冷可观察对象。

我认为你应该在saveUser方法中使用Completable而不是Observable<Void>,并且在遵循请求/响应或输入/输出模式的所有地方使用Single。当您实际上需要连续事件流时,应该使用Observable


1
感谢您的回复。我同意Single是网络请求的更好选择,因为它只有一个响应,但正如您可以在这个问题和许多其他关于RxJava 2.x的博客中所读到的那样,网络和数据库访问器应该使用Flowable来实现。 - Pablo Alonso González
2
我认为作者所指的是网络和数据库连接,它们的行为类似于事件流。如果我理解正确,这与HTTP请求/响应对或单个数据库查询不同。 - npace
你认为决定使用 Observable (Single/Completable) 还是 Flowable 的关键在于是否需要背压控制。这与源类型无关(冷源、网络/数据库访问器...)。 - Pablo Alonso González
3
是的 - 如果你的“流”只发出一个(Single)或零(Completable)个值,那么你不需要处理背压。如果你有一个例如与服务器的开放连接,并持续从它接收数据,那么你应该使用Flowable来处理可能数据到达得比你处理速度更快的情况。 - npace
2
更正:Single和Completable在1.x版本中存在,Retrofit for RxJava 1也支持它们。 - akarnokd

18

背压指的是当Observable发射项的速度超过操作符或订阅者消费它们的速度时所出现的问题。

基于此,如果你的Observable只会发射一个项,那么背压不是你需要考虑的问题,因此Flowable并不是一个好的选择。

所以实际问题是在saveUser方法中是否应该使用CompletableObservable,以及在findUser方法中是否应该使用SingleObservable。由于只有一个结果(成功或失败),为了简化接口并使其更清晰易懂,你应该明确地使用Completable/Single,否则很容易使 API 用户产生误解,觉得会发射多个值。


感谢您的回复。我同意Single是网络请求的更好选择,因为它只有一个响应,但正如您可以在这个问题和许多其他关于RxJava 2.x的博客中所读到的那样,网络和数据库访问器应该使用Flowable来实现。 - Pablo Alonso González
何时使用Flowable在访问数据库时,通过JDBC读取也是阻塞和拉取式的,并且由您通过为每个下游请求调用ResultSet.next()来控制。在这种情况下,我们从数据库中读取并且有多个结果,这不是您的情况。如果您仔细查看文档,问题更多的是在ObservableFlowable之间进行选择,因此当您有多个要发出的项目时,应该选择Flowable - Nicolas Filotto

10
基数是理解 CompletableMaybeSingle之间差异的一种方式:

  • Maybe<T>仅是具有基数0或1的Observable,即它表示可能存在或不存在的结果。
  • Single<T>是始终返回结果的Observable,即基数为1。
  • Completable可以被解释为类似于Observable<Void>,即基数为0。

因此,在您的情况下,您可以按以下方式更改存储库的签名:

Completable saveUser(...);

Single<User> findUser(...);

我没有提到Flowable,它们类似于带有背压Observable


3

据我所知,当您确信要获取一个项目时,应使用Single,否则会出现错误。 例如:GET - card /:id

如果您不太确定是否会获得一个项目,则Maybe可能是正确的解决方案。 例如:GET - card?license-plate = xvar3

当您只想知道操作是否完成时,请使用Completable。 例如:PUT或DETELE

当项目数量不太大时请使用Observable。

当您不知道将获得多少项目时,请使用Flowable。


0
  • 如果你的Observable(服务)以比观察者(客户端)更快的速度发出项目,则应使用Flowable以从背压机制中受益。 热Observable
  • 如果您的服务将每个请求发出一次,并且按需数据(大多数API的情况)则应将其视为冷Observable。在这种情况下,选择SingleMaybe。区别在于,如果您想处理服务在此情况下未发送响应或错误的情况,则可以通过利用onError()回调来使用Single。如果您不关心服务是否失败或成功,并且不介意空发射,请使用Maybe
  • 99%的数据库WRITE请求不返回任何内容(仅当您希望通过返回布尔值来确保数据时),在这种情况下,我会使用Completable执行操作并在结束时调用onComplete()

0

嗯...

我认为这个问题并不是一个简单的问题,因为你面临着更加复杂的情况。

例如: 保存用户(REST)> 保存用户(SQLlite)

您可能希望将 Rx 流链接成一个流。

所以,您可以声明

1.

Flowable<Response<Void>> saveUser(String username, String hashedPassword, boolean logged, User user);

然后使用其中一些: flatMap,concatMap,switchMap

2.

... 或者我认为更好的做法是不要混淆类的职责(您可以在许多地方使用相同的代码)

Single<Response<Void>> saveUser(String username, String hashedPassword, boolean logged, User user);

RestService.saveUser(...)
.toFlowable() // Transform into Flowable 
.switchMap{ saveToDB() }
.subscribeBy{ ... }
.addTo( yourDisposable )

3.

顺便提一下,如果你想要良好的错误处理,建议不要使用 Completable。你可以轻松地将 Retrofit.Response<Body> 包装在 SingleFlowable 中,以利用来自服务器的代码响应。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接