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

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
            })
    }

You can do this by publishing the search Observable through the timeout:

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. One of the ways is to use fromCallable for this and ignore its result (this also avoid duplication). The second lane will be unchanged and merged with the timeout lane to deliver the actual value.