Manage identical requests with RxJava

前端 未结 3 822
清歌不尽
清歌不尽 2021-01-16 21:00

Assume that I have a fetcher that fetches an image from a given link on a separate thread. The image will then be cached in memory. Once the image already gets cached, the f

3条回答
  •  迷失自我
    2021-01-16 21:49

    The clue is in the question: "Assume that I have a fetcher that fetches an image from a given link on a separate thread. The image will then be cached in memory."

    And the answer is the cache() operator:

    "remember the sequence of items emitted by the Observable and emit the same sequence to future Subscribers"

    from: https://github.com/ReactiveX/RxJava/wiki/Observable-Utility-Operators

    So, the following Observable should only fetch the image once, no matter how Subscribers subscribe to it:

    Observable cachedBitmap = fetchBitmapFrom(url).cache();
    

    EDIT:

    I think the following example proves that the upstream Observable is subscribed only once, even if multiple Subscriptions come in before the Observable has emitted anything. This should also be true for network requests.

    package com.example;
    
    import rx.Observable;
    import rx.Subscriber;
    import rx.schedulers.Schedulers;
    
    public class SimpleCacheTest {
    
        public static void main(String[] args) {
            final Observable cachedSomething = getSomething().cache();
    
            System.out.println("before first subscription");
            cachedSomething.subscribe(new SimpleLoggingSubscriber("1"));
    
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("before second subscription");
            cachedSomething.subscribe(new SimpleLoggingSubscriber("2"));
    
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("quit");
        }
    
        private static class SimpleLoggingSubscriber extends Subscriber {
    
            private final String tag;
    
            public SimpleLoggingSubscriber(final String tag) {
                this.tag = tag;
            }
            @Override
            public void onCompleted() {
                System.out.println("onCompleted (" + tag + ")");
            }
    
            @Override
            public void onError(Throwable e) {
                System.out.println("onError (" + tag + ")");
            }
    
            @Override
            public void onNext(T t) {
                System.out.println("onNext (" + tag + "): " + t);
            }
        }
    
        private static Observable getSomething() {
            return Observable.create(new Observable.OnSubscribe(){
    
                @Override
                public void call(Subscriber subscriber) {
                    System.out.println("going to sleep now...");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    subscriber.onNext(1);
                    subscriber.onCompleted();
                }
            }).subscribeOn(Schedulers.io());
        }
    }
    

    Output:

    before first subscription
    going to sleep now...
    before second subscription
    onNext (1): 1
    onNext (2): 1
    onCompleted (1)
    onCompleted (2)
    quit
    

提交回复
热议问题