private void downloadAndSave(final ObservableEmitter<ImageData> emitter, final Disposable disposable) {
                final File file = LocalStorage.getGeocacheDataFile(pseudoGeocode, url, true, true);
                if (url.startsWith("data:image/")) {
                    if (url.contains(";base64,")) {
                        ImageUtils.decodeBase64ToFile(StringUtils.substringAfter(url, ";base64,"), file);
                    } else {
                        Log.e("HtmlImage.fetchDrawableUncached: unable to decode non-base64 inline image");
                        emitter.onComplete();
                        return;
                    }
                } else if (disposable.isDisposed() || downloadOrRefreshCopy(url, file)) {
                    // The existing copy was fresh enough or we were unsubscribed earlier.
                    emitter.onComplete();
                    return;
                }
                if (onlySave) {
                    emitter.onComplete();
                    return;
                }
                AndroidRxUtils.computationScheduler.scheduleDirect(() -> {
                    final InternalImageData loaded = loadFromDisk();
                    final BitmapDrawable image = loaded.bitmapDrawable;
                    if (image != null) {
                        emitter.onNext(new ImageData(image, loaded.metadata, loaded.localUri));
                    } else {
                        emitter.onNext(new ImageData(getErrorImage(), null, null));
                    }
                    emitter.onComplete();
                });
            }
Caches are loaded from disk on a computation scheduler to avoid using more threads than cores while decoding
the image. Downloads happen on downloadScheduler, in parallel with image decoding.
main/src/main/java/cgeo/geocaching/network/HtmlImage.java