Retrofit 2 and Rxjava for file downloading in Android

This post demonstrates how to download a zip file or any other file regardless of file size using retrofit 2 and rxjava in Android. Retrofit 2 for handling network task, and rxjava for handling the background task control flow. Using OkHttpClient as the Http client for Retrofit 2, and Okio for saving content to disk.

1. Make sure the following are included as dependencies in the gradle file.

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'io.reactivex:rxjava:1.1.8'
compile 'io.reactivex:rxandroid:1.2.1'

2. The main method with the help of rxjava, composes every steps needed for downloading a file and save it to disk in Android. Replace https://github.com/ and yourusername/awesomegames/archive/master.zip with your actual url.

private void downloadZipFileRx() {
    // https://github.com/yourusername/awesomegames/archive/master.zip
    RetrofitInterface downloadService = createService(RetrofitInterface.class, "https://github.com/");
    downloadService.downloadFileByUrlRx("yourusername/awesomegames/archive/master.zip")
            .flatMap(processResponse())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(handleResult());

}

3. The service interface class, RetrofitInterface.java

public interface RetrofitInterface {

    // Regular Retrofit 2 GET request
    @Streaming
    @GET
    Call<ResponseBody> downloadFileByUrl(@Url String fileUrl);


    // Retrofit 2 GET request for rxjava
    @Streaming
    @GET
    Observable<Response<ResponseBody>> downloadFileByUrlRx(@Url String fileUrl);
}

4. All other methods that are used in the above method.

private Func1<Response<ResponseBody>, Observable<File>> processResponse() {
    return new Func1<Response<ResponseBody>, Observable<File>>() {
        @Override
        public Observable<File> call(Response<ResponseBody> responseBodyResponse) {
            return saveToDiskRx(responseBodyResponse);
        }
    };
}

private Observable<File> saveToDiskRx(final Response<ResponseBody> response) {
    return Observable.create(new Observable.OnSubscribe<File>() {
        @Override
        public void call(Subscriber<? super File> subscriber) {
            try {
                String header = response.headers().get("Content-Disposition");
                String filename = header.replace("attachment; filename=", "");

                new File("/data/data/" + getPackageName() + "/games").mkdir();
                File destinationFile = new File("/data/data/" + getPackageName() + "/games/" + filename);

                BufferedSink bufferedSink = Okio.buffer(Okio.sink(destinationFile));
                bufferedSink.writeAll(response.body().source());
                bufferedSink.close();

                subscriber.onNext(destinationFile);
                subscriber.onCompleted();
            } catch (IOException e) {
                e.printStackTrace();
                subscriber.onError(e);
            }
        }
    });
}

private Observer<File> handleResult() {
    return new Observer<File>() {
        @Override
        public void onCompleted() {
            Log.d(TAG, "onCompleted");
        }

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

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

public <T> T createService(Class<T> serviceClass, String baseUrl) {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(new OkHttpClient.Builder().build())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();
    return retrofit.create(serviceClass);
}

Complete example in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search