这可能会有点复杂,我对Observables和RX模式没有经验,所以请耐心等待:
假设您有一些返回Observable的任意SDK方法。您从一个类中使用该方法,该类除其他外负责检索数据,并在执行此操作时执行一些缓存,因此我们将其称为DataProvider
。然后,您还有另一个想要访问DataProvider
提供的数据的课程。我们暂时将其称为Consumer
。所以我们已经完成了设置。
所有模式朋友的旁注:我知道这不是MVP,它只是一个类似的例子,但是我面对的更复杂的问题应用
话虽如此,在类似Kotlin的伪代码中,描述的情况看起来像这样:
class Consumer(val provider: DataProvider) {
fun logic() {
provider.getData().subscribe(...)
}
}
class DataProvider(val sdk: SDK) {
fun getData(): Consumer {
val observable = sdk.getData()
observable.subscribe(/*cache data as it passes through*/)
return observable
}
}
class SDK {
fun getData(): Observable {
return fetchDataFromNetwork()
}
}
问题是,在sdk.subscribe()
调用DataProvider
之后我已经触发了我不想要的Observable subscribe()
方法。我希望DataProvider
能够默默地听 - 在这个例子中,触发应该由Consumer
完成。
那么这个问题的最佳RX兼容解决方案是什么?上面的伪代码中概述的那个绝对不是出于各种原因,其中之一是在Consumer
订阅Observable之前过早触发网络请求。在publish().autoComplete(2)
中致电subscribe()
之前,我已尝试使用DataProvider
,但这似乎并不是执行此类事情的规范方式。它只是感觉很乱。
编辑:通过SO的优秀"相关"功能我偶然发现另一个指向不同方向的问题,但有一个解决方案,也可以适用于flatMap()
。我以前知道那个,但从来没有真正使用它。对我来说似乎是一种可行的方式 - 您对此有何看法?
答案 0 :(得分:1)
是的,flatMap
可能是一个解决方案。此外,您可以将您的流拆分为小Observables
链:
public class DataProvider {
private Api api;
private Parser parser;
private Cache cache;
public Observable<List<User>> getUsers() {
return api.getUsersFromNetwork()
.flatMap(parser::parseUsers)
.map(cache::cacheUsers);
}
}
public class Api {
public Observable<Response> getUsersFromNetwork() {
//makes https request or whatever
}
}
public class Parser {
public Observable<List<User>> parseUsers(Response response) {
//parse users
}
}
public class Cache {
public List<User> cacheUsers(List<User> users) {
//cache users
}
}
易于测试,维护和替换实现(使用接口)。您还可以轻松地在流中插入其他步骤(例如,从服务器接收的日志/转换/更改数据)。
另一个非常方便的运算符是map
。基本上不是Observable<Data>
,而是只返回Data
。它可以使您的代码更简单。
答案 1 :(得分:1)
如果缓存步骤不应该修改链中的事件,则可以使用doOnNext()
运算符:
class DataProvider(val sdk: SDK) {
fun getData(): Observable<*> = sdk.getData().doOnNext(/*cache data as it passes through*/)
}