【问题标题】:Downloading files using OkHttp, Okio and RxJava使用 OkHttp、Okio 和 RxJava 下载文件
【发布时间】:2015-04-25 00:45:52
【问题描述】:

我正在尝试使用 OkHttp 下载文件并使用 Okio 写入磁盘。我还为这个过程创建了一个可观察的 rx。它正在工作,但它明显比我以前使用的(Koush 的 Ion 库)慢。

以下是我创建 observable 的方法:

public Observable<FilesWrapper> download(List<Thing> things) {
    return Observable.from(things)
        .map(thing -> {
            File file = new File(getExternalCacheDir() + File.separator + thing.getName());

            if (!file.exists()) {
                Request request = new Request.Builder().url(thing.getUrl()).build();
                Response response;
                try {
                    response = client.newCall(request).execute();
                    if (!response.isSuccessful()) new IOException();
                    else {
                        BufferedSink sink = Okio.buffer(Okio.sink(file));
                        sink.writeAll(response.body().source());
                        sink.close();
                    }
                } catch (IOException e) {
                    new IOException();
                }
            }

            return file;
        })
        .toList()
        .map(files -> new FilesWrapper(files);
}

有谁知道是什么原因导致速度变慢,或者我使用的运算符不正确?

【问题讨论】:

  • 你和以前一样在做什么?就目前而言,您一次只执行一个请求,而不是并行执行它们......
  • 您忘记了throw 以获取不成功的回复。

标签: android rx-java okhttp rx-android okio


【解决方案1】:

使用 flatMap 代替 map 将允许您并行执行下载:

public Observable<FilesWrapper> download(List<Thing> things) {
    return Observable.from(things)
            .flatMap(thing -> {
                File file = new File(getExternalCacheDir() + File.separator + thing.getName());
                if (file.exists()) {
                    return Observable.just(file);
                }

                final Observable<File> fileObservable = Observable.create(sub -> {
                    if (sub.isUnsubscribed()) {
                        return;
                    }

                    Request request = new Request.Builder().url(thing.getUrl()).build();

                    Response response;
                    try {
                        response = client.newCall(request).execute();
                        if (!response.isSuccessful()) { throw new IOException(); }
                    } catch (IOException io) {
                        throw OnErrorThrowable.from(OnErrorThrowable.addValueAsLastCause(io, thing));
                    }

                    if (!sub.isUnsubscribed()) {
                        try (BufferedSink sink = Okio.buffer(Okio.sink(file))) {
                            sink.writeAll(response.body().source());
                        } catch (IOException io) {
                            throw OnErrorThrowable.from(OnErrorThrowable.addValueAsLastCause(io, thing));
                        }
                        sub.onNext(file);
                        sub.onCompleted();
                    }

                });
                return fileObservable.subscribeOn(Schedulers.io());
            }, 5)
            .toList()
            .map(files -> new FilesWrapper(files));
}

我们使用 flatMap 上的 maxConcurrent 来限制每个订阅者的并发请求数。

【讨论】:

  • 你可能想给 flatMap 添加一个 maxConcurrent 值来限制并发网络调用的数量。
  • 在 OkHttp 的异步 enqueue API 中使用 Rx 的最佳方式是什么?
  • 杰西,你可以这样做的一种方法是:gist.github.com/alexwen/4b337bc669509a696b5b
猜你喜欢
  • 2015-07-08
  • 2015-07-09
  • 1970-01-01
  • 2016-09-12
  • 2023-03-30
  • 2015-09-16
  • 2020-10-26
  • 2017-05-27
  • 2018-06-12
相关资源
最近更新 更多