简体   繁体   English

如何使用Retrofit2下载文件?

[英]How to download a file with Retrofit2?

How can I download a file(image/video) from my PHP server using Retrofit2 ? 如何使用Retrofit2从我的PHP服务器下载 文件(图像/视频)

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. 我发现这篇文章SO上处理了某个下载错误,但对我来说并不是很清楚。 Could anyone point me to the right direction? 有人能指出我正确的方向吗?

UPDATE: 更新:

Here is my code: 这是我的代码:

FileDownloadService.java FileDownloadService.java

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

MainActivity.java ( @Blackbelt 's solution) MainActivity.java@Blackbelt的解决方案)

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. USB调试处于活动状态时会收到FileNotFoundException ,否则会收到NetworkOnMainThreadException

MainActivity.java: ( @Emanuel 's solution) MainActivity.java :( @Emanuel的解决方案)

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 . 我得到一个FileNotFoundException

This is a little example showing how to download the Retrofit JAR file. 这是一个显示如何下载Retrofit JAR文件的小例子。 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: 这是一个使用该接口的Java类:

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 . 下载文件,您可能希望响应的原始InputStream和写入是sdcard上的内容。 To do so, you should use ResponseBody as T for your return type, Call<ResponseBody> . 为此,您应该将ResponseBody用作返回类型的TCall<ResponseBody> You will then use Retrofit to enqueue a 然后,您将使用Retrofit enqueue

Callback<ResponseBody>

and when the onResponse 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 ) 调用,你可以检索InputStream ,使用response.byteStream() ,从中读取,并写下你在SD卡上读到的内容(看看这里

If anybody stumbles upon this response this is how i did it using retrofit in conjunction with Rx. 如果有人偶然发现这个反应,这就是我如何使用rx结合改装来做到这一点。 Every downloaded file is cached, and any subsequent requests with the same url will return the already downloaded file. 每个下载的文件都被缓存,并且具有相同URL的任何后续请求将返回已下载的文件。

In order to use this just subscribe to this observable and pass your url. 为了使用它,只需订阅此observable并传递您的网址。 This will save your file in downloads directory so make sure to ask for permissions if your app targets API 23 or greater. 这会将您的文件保存在下载目录中,因此如果您的应用面向API 23或更高版本,请务必询问权限。

  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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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