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
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 super Integer> 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