简体   繁体   中英

How to download a file with Retrofit2?

How can I download a file(image/video) from my PHP server using Retrofit2 ?

I wasn't able to find any resources or tutorials online on how to proceed; I found this post that treats a certain download error on SO but it's not very clear to me. Could anyone point me to the right direction?

UPDATE:

Here is my code:

FileDownloadService.java

public interface FileDownloadService {
    @GET(Constants.UPLOADS_DIRECTORY + "/{filename}")
    @Streaming
    Call<ResponseBody> downloadRetrofit(@Path("filename") String fileName);
}

MainActivity.java ( @Blackbelt 's solution)

private void downloadFile(String filename) {
    FileDownloadService service = ServiceGenerator
            .createService(FileDownloadService.class, Constants.SERVER_IP_ADDRESS);
    Call<ResponseBody> call = service.downloadRetrofit("db90408a4bb1ee65d3e09d261494a49f.jpg");

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(final Response<ResponseBody> response, Retrofit retrofit) {
            try {
                InputStream is = response.body().byteStream();
                FileOutputStream fos = new FileOutputStream(
                        new File(Environment.getExternalStorageDirectory(), "image.jpg")
                );
                int read = 0;
                byte[] buffer = new byte[32768];
                while ((read = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, read);
                }

                fos.close();
                is.close();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "Exception: " + e.toString(), Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(MainActivity.this, "Failed to download file...", Toast.LENGTH_LONG).show();
        }
    });
}

I get a FileNotFoundException when USB debugging is active, & a NetworkOnMainThreadException when not.

MainActivity.java: ( @Emanuel 's solution)

private void downloadFile(String filename) {
    FileDownloadService service = ServiceGenerator
            .createService(FileDownloadService.class, Constants.SERVER_IP_ADDRESS);
    Call<ResponseBody> call = service.downloadRetrofit("db90408a4bb1ee65d3e09d261494a49f.jpg");

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(final Response<ResponseBody> response, Retrofit retrofit) {
            Log.i(TAG, "external storage = " + (Environment.getExternalStorageState() == null));
            Toast.makeText(MainActivity.this, "Downloading file... " + Environment.getExternalStorageDirectory(), Toast.LENGTH_LONG).show();

            File file = new File(Environment.getDataDirectory().toString() + "/aouf/image.jpg");
            try {
                file.createNewFile();
                Files.asByteSink(file).write(response.body().bytes());
            } catch (Exception e) {
                Toast.makeText(MainActivity.this,
                        "Exception: " + e.toString(),
                        Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(MainActivity.this, "Failed to download file...", Toast.LENGTH_LONG).show();
        }
    });
}

I get a FileNotFoundException .

This is a little example showing how to download the Retrofit JAR file. You can adapt it to your needs.

This is the interface:

import com.squareup.okhttp.ResponseBody;
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Path;

interface RetrofitDownload {
    @GET("/maven2/com/squareup/retrofit/retrofit/2.0.0-beta2/{fileName}")
    Call<ResponseBody> downloadRetrofit(@Path("fileName") String fileName);
}

And this is a Java class using the interface:

import com.google.common.io.Files;
import com.squareup.okhttp.ResponseBody;
import retrofit.Call;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;

import java.io.File;
import java.io.IOException;

public class Main {

    public static void main(String... args) {
        Retrofit retrofit = new Retrofit.Builder().
                baseUrl("http://repo1.maven.org").
                build();

        RetrofitDownload retrofitDownload = retrofit.create(RetrofitDownload.class);

        Call<ResponseBody> call = retrofitDownload.downloadRetrofit("retrofit-2.0.0-beta2.jar");

        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Response<ResponseBody> response, Retrofit retrofitParam) {
                File file = new File("retrofit-2.0.0-beta2.jar");
                try {
                    file.createNewFile();
                    Files.asByteSink(file).write(response.body().bytes());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Throwable t) {
            }
        });
    }
}

to download a file, you might want the raw InputStream of the response and write is content on the sdcard . To do so, you should use ResponseBody as T for your return type, Call<ResponseBody> . You will then use Retrofit to enqueue a

Callback<ResponseBody>

and when the onResponse

@Override
public void onResponse(final Response<ResponseBody> response, Retrofit retrofit) {

is invoked, you can retrieve the InputStream , with response.byteStream() , read from it, and write what you read on the sdcard (have a look here )

If anybody stumbles upon this response this is how i did it using retrofit in conjunction with Rx. Every downloaded file is cached, and any subsequent requests with the same url will return the already downloaded file.

In order to use this just subscribe to this observable and pass your url. This will save your file in downloads directory so make sure to ask for permissions if your app targets API 23 or greater.

  public Observable<File> getFile(final String filepath) {
    URL url = null;
    try {
        url = new URL(filepath);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
    final String name = url.getPath().substring(url.getPath().lastIndexOf("/") + 1);
    final File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), name);
    if (file.exists()) {
        return Observable.just(file);
    } else {
        return mRemoteService.getFile(filepath).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 {

                            final File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsoluteFile(), name);

                            BufferedSink sink = Okio.buffer(Okio.sink(file));
                            sink.writeAll(responseBodyResponse.body().source());
                            sink.flush();
                            sink.close();
                            subscriber.onNext(file);
                            subscriber.onCompleted();
                            file.deleteOnExit();
                        } catch (IOException e) {
                            Timber.e("Save pdf failed with error %s", e.getMessage());
                            subscriber.onError(e);
                        }
                    }
                });
            }
        });
    }
}

Retrofit part of the call

@Streaming
@GET
Observable<retrofit2.Response<ResponseBody>> getFile(@Url String fileUrl);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM