简体   繁体   English

如果RxJava observable需要很长时间,你如何显示微调器?

[英]How do you show spinner if RxJava observable takes to long?

I feel like someone has to have tried this, but I can't figure out a nice way to do something if an observable takes to long. 我觉得有人必须尝试这个,但如果一个观察者需要很长时间,我无法想出一个很好的方法来做某事。

This is the flow I want. 这是我想要的流程。

Start a search.
If the search takes longer than some time,
    show a spinner or show progress bar.
When finished do subscription action and hide spinner/progress bar.

The closest I can think of is like a Zip 我能想到的最接近的就像一个Zip

manager.search(searchTerm)
       .zip(Observable.Timer(1, TimeUnit.SECONDS))
       .subscribe(
           // if the search is non null then we are good
           // if the long time is non 0 we need to show spinner
       );

Is there something better to do? 还有更好的事吗? I have been trying all day with no success. 我整天都在努力,没有成功。 In a perfect world I feel like I would want something like 在一个完美的世界里,我觉得我会想要这样的东西

manager.search(searchTerm)
       .timeout(i -> /* do timeout stuff */, 1, TimeUnit.SECONDS)
       .subscribe(item -> /* do search result stuff */);

You can do this by publishing the search Observable through the timeout: 您可以通过超时发布搜索Observable来完成此操作:

Observable<Integer> source = Observable.just(1).delay(5, TimeUnit.SECONDS);

source
.doOnSubscribe(() -> System.out.println("Starting"))
.publish(o -> 
    o.timeout(1, TimeUnit.SECONDS, Observable.<Integer>fromCallable(() -> {
        System.out.println("Spinning...");
        return null;
    })).ignoreElements().mergeWith(o)
)
.toBlocking()
.subscribe(v -> {
    System.out.println("Hide spinner if shown.");
    System.out.println(v);
});

This works by splitting the source into two hot lanes: the first lane will run a timeout operator which when times out, starts another Observable with the side-effect that shows the spinning control. 这可以通过将源分成两个热通道来实现:第一个通道将运行一个timeout运算符,当timeout时,启动另一个具有显示旋转控件的副作用的Observable。 One of the ways is to use fromCallable for this and ignore its result (this also avoid duplication). 其中一种方法是使用fromCallable并忽略其结果(这也避免重复)。 The second lane will be unchanged and merged with the timeout lane to deliver the actual value. 第二个通道将保持不变并与超时通道合并以提供实际值。

Today i found a bit odd but working solution. 今天我发现有点奇怪但有效的解决方案。 Idea is to use interval instead of timer. 想法是使用间隔而不是计时器。

    fun <T> base_delayed_progress_observable(source: Observable<T>): Observable<T>
    {
        val timer = Observable.interval(100, TimeUnit.MILLISECONDS) //Creates observable that will emit Long++ each 100 miliseconds
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnNext(
                    {
                        if (it == 10L)//Here we check current timer value. For example here i check if it is 1 second gone (100 miliseconds * 10 = 1 second)
                        {
                            //here we put all we need to show progress/spinner an so on
                        }
                    })

        return Observable.zip(source, timer,
            BiFunction<T, Long, T> { t1, t2 ->
                //Here we return our original Obervable zipped with timer
                //Timer will be cancelled when our source Observable gets to OnComplete
                return@BiFunction t1
            }).doFinally(
            {
                //Here we can dismiss all progress dilogs/spinner
            })
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM