Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
375 views
in Technique[技术] by (71.8m points)

android retrofit download progress

I'm new to retrofit. I've searched but didn't found a simple answer. I want to know how can I show progress of download in Notification bar or at least show a progress dialog which specifies the percent of process and size of downloading file. Here is my code:

public interface ServerAPI {
    @GET
    Call<ResponseBody> downlload(@Url String fileUrl);

    Retrofit retrofit =
            new Retrofit.Builder()
                    .baseUrl("http://192.168.43.135/retro/") 
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

}

public void download(){
    ServerAPI api = ServerAPI.retrofit.create(ServerAPI.class);
    api.downlload("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png").enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            try {
                File path = Environment.getExternalStorageDirectory();
                File file = new File(path, "file_name.jpg");
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                IOUtils.write(response.body().bytes(), fileOutputStream);
            }
            catch (Exception ex){
            }
        }


        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
        }
    });
}

please guide me if you can. thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to create a specific OkHttp client which will intercept the network requests and send updates. This client should only be used for downloads.

First you are going to need an interface, like this one:

public interface OnAttachmentDownloadListener {
    void onAttachmentDownloadedSuccess();
    void onAttachmentDownloadedError();
    void onAttachmentDownloadedFinished();
    void onAttachmentDownloadUpdate(int percent);
}

Your download call should return a ResponseBody, which we will extend from to be able to get the download progress.

private static class ProgressResponseBody extends ResponseBody {

    private final ResponseBody responseBody;
    private final OnAttachmentDownloadListener progressListener;
    private BufferedSource bufferedSource;

    public ProgressResponseBody(ResponseBody responseBody, OnAttachmentDownloadListener progressListener) {
        this.responseBody = responseBody;
        this.progressListener = progressListener;
    }

    @Override public MediaType contentType() {
        return responseBody.contentType();
    }

    @Override public long contentLength() {
        return responseBody.contentLength();
    }

    @Override public BufferedSource source() {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(responseBody.source()));
        }
        return bufferedSource;
    }

    private Source source(Source source) {
        return new ForwardingSource(source) {
            long totalBytesRead = 0L;

            @Override public long read(Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);

                totalBytesRead += bytesRead != -1 ? bytesRead : 0;

                float percent = bytesRead == -1 ? 100f : (((float)totalBytesRead / (float) responseBody.contentLength()) * 100);

                if(progressListener != null)
                    progressListener.onAttachmentDownloadUpdate((int)percent);

                return bytesRead;
            }
        };
    }
}

Then you will need to create your OkHttpClient like this

public OkHttpClient.Builder getOkHttpDownloadClientBuilder(OnAttachmentDownloadListener progressListener) {
    OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();

    // You might want to increase the timeout
    httpClientBuilder.connectTimeout(20, TimeUnit.SECONDS);
    httpClientBuilder.writeTimeout(0, TimeUnit.SECONDS);
    httpClientBuilder.readTimeout(5, TimeUnit.MINUTES);

    httpClientBuilder.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            if(progressListener == null) return chain.proceed(chain.request());

        Response originalResponse = chain.proceed(chain.request());
        return originalResponse.newBuilder()
                .body(new ProgressResponseBody(originalResponse.body(), progressListener))
                .build();
        }
    });

    return httpClientBuilder;
}

Finally you only have to create your Retrofit client a different way, by passing your new OkHttp client. Based on your code, you can use something like this:

 public Retrofit getDownloadRetrofit(OnAttachmentDownloadListener listener) {

    return new Retrofit.Builder()
                .baseUrl("http://192.168.43.135/retro/") 
                .addConverterFactory(GsonConverterFactory.create())
                .client(getOkHttpDownloadClientBuilder(listener).build())
                .build();

}

Your listener will handle the creation of your notification or whatever else you want.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.9k users

...