【问题标题】:Single that emits a value that passed function returned发出传递函数返回的值的单个
【发布时间】:2017-11-06 21:58:10
【问题描述】:

我想要一个调用某个函数然后以该函数返回的值完成的 Single。

以下是类似的:

Single.fromCallable(this::func);

问题在于每次添加订阅者时它都会调用 this::func。因此,如果 this::func 计算调用次数,那么 single 将返回 3 给它获得的第三个订阅者。
我认为这是一个问题,因为如果 this::func 是一个长时间运行的操作会怎样。
我不明白,这是否意味着 Single::onComplete 已被调用两次?我认为这是不可能的,而且没有意义,因为,一件事情怎么可能完成两次?

由于我是一名 Android 程序员,Single::fromFuture 在这里不起作用,有什么替代方法吗?

我将通过以下示例演示我的问题:

class SingleFromCallableTest {

    int funcCalls = 0;

    int func(){
        return funcCalls++;
    }

    @Test
    public void run(){
        Single<Integer> source = Single.fromCallable(this::func);
        source.subscribe(System.out::println);  // prints 1
        source.subscribe(System.out::println);  // prints 2
    }
}

IMO,不应该调用第二个订阅者,因为 Single 应该只成功一次 IMO。 就像 SingleSubject 一样,一旦调用 onSuccess,就不能再成功了。

如果Single.fromCallable 会按照它认为应该的方式工作,那么在前面的示例中,source 甚至可以在第一个订阅者订阅之前完成,这意味着只有以下订阅方式才有意义:

Single.fromCallable(this::func).subscribe(System.out.println);

但实际上,即使那样,也可能无法捕获 single 发出的值,也许这就是不可能的。

【问题讨论】:

    标签: java android rx-java


    【解决方案1】:

    #fromCallable 方法是一个工厂,每次都会返回一个新的 Single。在每次订阅时,您都会订阅一个新的单曲。因此,将为每个订阅者调用该函数。如果要缓存该值,则可以使用 #cache 运算符。请查看提供的两个测试。

    测试“notCached”将为每个订阅调用该函数。测试“缓存”将仅调用该函数一次。如果您想共享结果,只需重新使用 create Single#fromCallable 和 #cache 运算符。

    环境

    dependencies {
    compile 'io.reactivex.rxjava2:rxjava:2.1.6'
    compile 'org.mockito:mockito-core:2.11.0'
    testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0")
    testRuntime("org.junit.jupiter:junit-jupiter-engine:5.0.0")
    

    测试

    @Test
    void notCached() throws Exception {
        Callable<Integer> mock = mock(Callable.class);
    
        when(mock.call()).thenReturn(10);
    
        Single<Integer> integerSingle = Single.fromCallable(mock);
    
        Disposable subscribe1 = integerSingle.subscribe();
        Disposable subscribe2 = integerSingle.subscribe();
    
        verify(mock, times(2)).call();
    }
    
    @Test
    void cached() throws Exception {
        Callable<Integer> mock = mock(Callable.class);
    
        when(mock.call()).thenReturn(10);
    
        Single<Integer> integerSingle = Single.fromCallable(mock).cache();
    
        Disposable subscribe1 = integerSingle.subscribe();
        Disposable subscribe2 = integerSingle.subscribe();
        Disposable subscribe3 = integerSingle.subscribe();
        Disposable subscribe4 = integerSingle.subscribe();
    
        verify(mock, times(1)).call();
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 2013-06-01
    • 2021-03-25
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 2021-08-14
    相关资源
    最近更新 更多