【问题标题】:Is it possible to show progress bar when download via Retrofit 2 Asynchronous?通过 Retrofit 2 Asynchronous 下载时是否可以显示进度条?
【发布时间】:2017-06-13 01:25:57
【问题描述】:
@Streaming
@GET
Call<ResponseBody> downloadSong(@Url String url);

以上代码用于通过改造异步下载文件。我想知道下载进度,如果有暂停/恢复的可能也请回答

【问题讨论】:

    标签: android download retrofit retrofit2 progress


    【解决方案1】:

    我终于得到了答案。

    为此,我们需要使用 rxjava 和改造。

    下载ProgressListener.java

    public interface DownloadProgressListener {
        void update(long bytesRead, long contentLength, boolean done);  
    }
    

    下载ProgressResponseBody.java

    public class DownloadProgressResponseBody extends ResponseBody {
    
        private ResponseBody responseBody;
        private DownloadProgressListener progressListener;
        private BufferedSource bufferedSource;
    
        public DownloadProgressResponseBody(ResponseBody responseBody,
                                            DownloadProgressListener 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);
                    // read() returns the number of bytes read, or -1 if this source is exhausted.
                    totalBytesRead += bytesRead != -1 ? bytesRead : 0;
    
                    if (null != progressListener) {
                        progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                    }
                    return bytesRead;
                }
            };
    
        }
    }
    

    下载ProgressInterceptor.java

    public class DownloadProgressInterceptor implements Interceptor {
    
        private DownloadProgressListener listener;
    
        public DownloadProgressInterceptor(DownloadProgressListener listener) {
            this.listener = listener;
        }
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response originalResponse = chain.proceed(chain.request());
    
            return originalResponse.newBuilder()
                    .body(new DownloadProgressResponseBody(originalResponse.body(), listener))
                    .build();
        }
    }
    

    下载.java

    public class Download implements Parcelable {
    
        private int progress;
        private long currentFileSize;
        private long totalFileSize;
    
        public int getProgress() {
            return progress;
        }
    
        public void setProgress(int progress) {
            this.progress = progress;
        }
    
        public long getCurrentFileSize() {
            return currentFileSize;
        }
    
        public void setCurrentFileSize(long currentFileSize) {
            this.currentFileSize = currentFileSize;
        }
    
        public long getTotalFileSize() {
            return totalFileSize;
        }
    
        public void setTotalFileSize(long totalFileSize) {
            this.totalFileSize = totalFileSize;
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(this.progress);
            dest.writeLong(this.currentFileSize);
            dest.writeLong(this.totalFileSize);
        }
    
        public Download() {
        }
    
        protected Download(Parcel in) {
            this.progress = in.readInt();
            this.currentFileSize = in.readLong();
            this.totalFileSize = in.readLong();
        }
    
        public static final Parcelable.Creator<Download> CREATOR = new Parcelable.Creator<Download>() {
            @Override
            public Download createFromParcel(Parcel source) {
                return new Download(source);
            }
    
            @Override
            public Download[] newArray(int size) {
                return new Download[size];
            }
        };
    }
    

    下载服务.java

    public interface DownloadService {
        @Streaming
        @GET
        Observable<ResponseBody> download(@Url String url);
    }
    

    下载API.java

    public class DownloadAPI {
        private static final String TAG = "DownloadAPI";
        private static final int DEFAULT_TIMEOUT = 15;
        public Retrofit retrofit;    
    
        public DownloadAPI(String url, DownloadProgressListener listener) {
    
            DownloadProgressInterceptor interceptor = new DownloadProgressInterceptor(listener);
    
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(interceptor)
                    .retryOnConnectionFailure(true)
                    .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .build();
    
            retrofit = new Retrofit.Builder()
                    .baseUrl(url)
                    .client(client)        
                  .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
        }
    
        public void downloadAPK(@NonNull String url, final File file, Subscriber subscriber) {
            Log.d(TAG, "downloadAPK: " + url);
    
            retrofit.create(DownloadService.class)
                        .download(url)
                        .subscribeOn(Schedulers.io())
                        .unsubscribeOn(Schedulers.io())
                        .map(new Func1<ResponseBody, InputStream>() {
                            @Override
                            public InputStream call(ResponseBody responseBody) {
                                return responseBody.byteStream();
                            }
                        })
                        .observeOn(Schedulers.computation())
                        .doOnNext(new Action1<InputStream>() {
                            @Override
                            public void call(InputStream inputStream) {
                                try {
                                    FileUtils.writeFile(inputStream, file);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    throw new CustomizeException(e.getMessage(), e);
                                }
                            }
                        })
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(subscriber);
            }
    
    
        }
    

    用法

    DownloadProgressListener listener = new DownloadProgressListener() {
                @Override
                public void update(long bytesRead, long contentLength, boolean done) {
                    Download download = new Download();
                    download.setTotalFileSize(contentLength);
                    download.setCurrentFileSize(bytesRead);
                    int progress = (int) ((bytesRead * 100) / contentLength);
                    download.setProgress(progress);
    
                    sendNotification(download);
                }
            };
            File outputFile = new File(Environment.getExternalStoragePublicDirectory
                    (Environment.DIRECTORY_DOWNLOADS), "file.apk");
            String baseUrl = StringUtils.getHostName(apkUrl);
    
            new DownloadAPI(baseUrl, listener).downloadAPK(apkUrl, outputFile, new Subscriber() {
                @Override
                public void onCompleted() {
                    downloadCompleted();
                }
    
                @Override
                public void onError(Throwable e) {
                    e.printStackTrace();
                    downloadCompleted();
                    Log.e(TAG, "onError: " + e.getMessage());
                }
    
                @Override
                public void onNext(Object o) {
    
                }
            });
    

    【讨论】:

    • 所以我正在阅读 rxjava 教程来应用这种方法,希望你有一个很好的性能来上传多个通知的进度?
    • @Bincy Baby 请告诉我必须添加的所有依赖项。
    • 你必须在你的项目中添加改造和 rxjava 1
    • 嗨。你能帮助我吗 ? stackoverflow.com/questions/49146348/…
    【解决方案2】:

    我只是使用@Jan post的代码,但是遇到了无法下载并且只有一次回调的问题,经过多次尝试,我找到了解决方案:

    OkHttpClient client = new OkHttpClient.Builder()
                // .addInterceptor(interceptor)
                .addNetworkInterceptor(interceptor)
    

    只需将拦截器更改为 networkInterceptor 它运行正常! 祝你好运!

    【讨论】:

    • 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
    • 感谢您的建议,但这只是对 Jan 答案的补充,我想在 Jan 的答案下方添加评论,但我没有足够的声誉。
    猜你喜欢
    • 1970-01-01
    • 2016-01-25
    • 2020-12-04
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    相关资源
    最近更新 更多