订阅一个Observable而不触发它,然后传递它

时间:2016-02-20 00:01:51

标签: java rx-java reactive-programming

这可能会有点复杂,我对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()。我以前知道那个,但从来没有真正使用它。对我来说似乎是一种可行的方式 - 您对此有何看法?

2 个答案:

答案 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*/)
}