RxJava,OkHttp,Okio,Android中的文件下载程序

时间:2015-04-29 11:06:57

标签: android rx-java okhttp

我正在尝试将此工作文件下载代码转换为Reactive。但由于我对RxJava的了解不多而陷入困境。你能帮我把它变成反应吗?

public void downloadFile(MessageComponent media) {
        Request request = new Request.Builder()
                .url(media.getMediaUrl())
                .build();

        Call call = http_client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                Log.e(TAG, "Failed to execute " + request, e);
            }

            @Override
            public void onResponse(Response response) throws IOException {
                if (!response.isSuccessful()) {
                    throw new IOException("Unexpected code " + response);
                }
                String mimeType = MimeTypeMap.getFileExtensionFromUrl(media.getMediaUrl());
                File file = new File(helper.getTmpFolder() + "/" + helper.generateUniqueName() + "test." + mimeType);
                BufferedSink sink = Okio.buffer(Okio.sink(file));
                sink.writeAll(response.body().source());
                sink.close();
                Log.d(TAG, "downloadFileFromServer done: " + media.getMediaUrl());
            }
        });
    } 

这是我到目前为止所写的,并没有得到任何结果或错误:

public void downloadFile(MessageComponent media){
   Observable<String> downloadObservable = Observable.create(
            sub -> {
                Request request = new Request.Builder()
                        .url(media.getMediaUrl())
                        .build();
                Response response = null;
                try {
                    response = http_client.newCall(request).execute();
                    if (!response.isSuccessful()) new IOException();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                sub.onNext(response.toString());
            }
    );

    Subscriber<String> mySubscriber = new Subscriber<String>() {
        @Override
        public void onNext(String responseString) {
            Log.d(TAG, "works: " + responseString);
        }

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
            Log.e(TAG, e.getMessage(), e);
        }
    };
    downloadObservable
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(mySubscriber);
    mySubscriber.unsubscribe();

}

2 个答案:

答案 0 :(得分:4)

您的代码有一些错误,这可能解释了预期的行为不是您得到的。

可观察到的合同错误

Reactive Extensions(RxJava是它的一个实现)基于这个合同:你可以在onNext上多次收到通知,然后,你会在错误或完成时通知一次(或从不......)。

onNext* (onComplete | onError)?

因此,您的Observable代码可以重写为此代码,以发出您的流错误或已完成的事实。

Observable<String> downloadObservable = Observable.create(
        sub -> {
            Request request = new Request.Builder()
                    .url(media.getMediaUrl())
                    .build();
            Response response = null;
                response = http_client.newCall(request).execute();
                if (response.isSuccessful()) {
                    sub.onNext(response.toString());
                    sub.onCompleted();
                } else {
                    sub.onError(new IOException());
                }
        }
);

取消订阅早期

您在订阅后取消订阅,因此您的Observable可能没有时间执行。

downloadObservable
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(mySubscriber);
mySubscriber.unsubscribe();

如果Observable完成,则会取消订阅。所以在这种情况下不必取消订阅。

答案 1 :(得分:1)

此问题与以下内容具有相同的最终目标,即下载文件并将其保存到Android中的磁盘:

Downloading files using OkHttp, Okio and RxJava

Download and write a file with Retrofit and RxJava

Here是下载文件并将其保存到Android中的磁盘的一个很好的示例。

以下是对上述链接示例的修改,而不使用lambda表达式。

1.确保在app build gradle

中包含必要的依赖项
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
compile 'io.reactivex:rxjava:1.1.5'
compile 'io.reactivex:rxandroid:1.1.0'

2.Retrofit 2界面,@ Streaming用于下载大文件。

public interface RetrofitApi {
    @Streaming
    @GET
    Observable<Response<ResponseBody>> downloadFile(@Url String fileUrl);
}

3.使用Retrofit 2和rxjava下载文件并将其保存到磁盘的代码。将下面代码中的baseUrl和url路径更新为您需要下载的文件的实际URL。

public void downloadZipFile() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://my.resources.com/")
            .client(new OkHttpClient.Builder().build())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();
    RetrofitApi downloadService = retrofit.create(RetrofitApi.class);

    downloadService.downloadFile("resources/archive/important_files.zip")
            .flatMap(new Func1<Response<ResponseBody>, Observable<File>>() {
                @Override
                public Observable<File> call(final Response<ResponseBody> responseBodyResponse) {
                    return Observable.create(new Observable.OnSubscribe<File>() {
                        @Override
                        public void call(Subscriber<? super File> subscriber) {
                            try {
                                // you can access headers of response
                                String header = responseBodyResponse.headers().get("Content-Disposition");
                                // this is specific case, it's up to you how you want to save your file
                                // if you are not downloading file from direct link, you might be lucky to obtain file name from header
                                String fileName = header.replace("attachment; filename=", "");
                                // will create file in global Music directory, can be any other directory, just don't forget to handle permissions
                                File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsoluteFile(), fileName);

                                BufferedSink sink = Okio.buffer(Okio.sink(file));
                                // you can access body of response
                                sink.writeAll(responseBodyResponse.body().source());
                                sink.close();
                                subscriber.onNext(file);
                                subscriber.onCompleted();
                            } catch (IOException e) {
                                e.printStackTrace();
                                subscriber.onError(e);
                            }
                        }
                    });
                }
            })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<File>() {
                            @Override
                            public void onCompleted() {
                                Log.d("downloadZipFile", "onCompleted");
                            }

                            @Override
                            public void onError(Throwable e) {
                                e.printStackTrace();
                                Log.d("downloadZipFile", "Error " + e.getMessage());
                            }

                            @Override
                            public void onNext(File file) {
                                Log.d("downloadZipFile", "File downloaded to " + file.getAbsolutePath());
                            }
                       });
}