美文网首页
RetroHttp(六) — 下载进度

RetroHttp(六) — 下载进度

作者: 奔跑的佩恩 | 来源:发表于2021-04-06 10:28 被阅读0次

前言

RetroHttp的下载功能使用过程中,出现了下载进度无法实时显示的问题,然后我做了些优化,下面就来讲讲吧。
更多关于RetroHttp,大家可参考以下文章:
RetroHttp(一) — 下载使用介绍
RetroHttp(二) — 下载支持增量更新
RetroHttp(三) — kotlin版网络请求
RetroHttp(四) — 实现串联请求
RetroHttp(五) — 并发请求

今天涉及内容:

  1. RetroHttp 关于下载,优化前的调用方式
  2. 下载无法显示进度的原因分析
  3. 优化下载的调用方式

一. RetroHttp 关于下载,优化前的调用方式

RetroHttp0.4.3版本之前,我们要调用下载的话,是像下面这样调用的:

    //是否增量更新的标志
    private boolean mUpdate=false;

    private void updateApk(){
        String url=null;
        
        //此处mUpdate你要先根据业务逻辑赋值为true或false
        if(mUpdate){
            //增量更新的url
            url="https://xxxx/xxx/test.patch";//示例代码
        }else{
            //全量更新的url
            url="https://xxxx/xxx/test_2.0.0.apk";//示例代码
        }
        LogUtil.i("=========mUpdate======"+mUpdate);
        LogUtil.i("=========url======"+url);

        int firstIndex=url.lastIndexOf("/")+1;
        int lastIndex=url.length();
        String fileName=url.substring(firstIndex,lastIndex);
        LogUtil.i("=========fileName======"+fileName);
        //启动下载
        ProgressDialog progressDialog = DownLoadHelper.getInstance().showDownLoading(mContext);
        DownLoadHelper.getInstance().setFileName(fileName)//设置下载文件名
                .setIcon(R.mipmap.ic_launcher)//设置apk图标资源id
                .setAuthorityTag("com.p.atestdemo")//设置要与清单文件的 provider 中配置的authorities值一致
                .setIncrementUpdate(mUpdate)//是否开启增量更新(true:开启,false:关闭,此行代码不设置会默认全量更新)
                .downLoadFile(url, MainActivity.this, new DownLoadHelper.DownloadListener() {
                    @Override
                    public void onStart() {

                    }

                    @Override
                    public void update(int progress, boolean done) {
                        progressDialog.setProgress((int) (progress * 1f));
                    }

                    @Override
                    public void onCompleted() {
                        progressDialog.dismiss();
                    }

                    @Override
                    public void onError(String err) {
                        progressDialog.dismiss();
                        LogUtil.i("=========下载失败====="+err);
                        if(DownLoadHelper.getInstance().isDeltaFileFailed(err)){
                            LogUtil.i("=========增量更新下载失败====="+err);
                            //增量更新下载失败的逻辑(一般发rx通知出来,然后改全量更新)
                            //......
                        }else{
                            LogUtil.i("=========全量更新下载失败====="+err);
                            //全量更新下载失败的逻辑(一般提示退出app)
                            //......
                        }
                    }
                });
    }

然而在使用过程中,我们会发现下载进度框在显示的时候,竟然不更新,下载进度一直显示是0,但实际上文件是在下载的。接着让我们来看看问题所在。

二.下载无法显示进度的原因分析

追查代码发现,下载目标文件的总大小contentLength来自responseBody.contentLength(),而responseBody.contentLength()值一直是-1。在http通讯过程中,contentLength()源自通讯字节头中的ContenLength属性,ContenLength中一般会加载要下载的文件总大小,但是由于okhttp3基本采用gzip压缩方式下载,导致通讯字节头中Transfer-Encoding: chunked,无法获取准确ContenLength值,于是网上提出一种解决办法,在发起下载通讯时,字节头中添加如下代码:

        // 设置统一请求参数
        Request.Builder newRequest = oldRequest.newBuilder()
                .method(oldRequest.method(), oldRequest.body())
                // 设置请求头
                .addHeader("Accept-Encoding", "identity")//强迫服务器不走压缩,以得到文件总大小

使得在通讯时,申请服务器禁用压缩方式,这样就能获得具体的ContenLength值。但是在实际使用过程中我们会发现并不是所有的下载通讯请求,在返回的数据中字节头都会含ContenLength属性。让我们打开cmd,输入curl -i 下载链接看看返回信息的字节头:

curl -i https://xxxx/xxxx/xxxx/test.apk
HTTP/1.1 200 OK
Date: Tue, 06 Apr 2021 01:51:53 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: acw_tc=76b20f6916176739129186578e7f31209e1a24c1af4e3d16fbaecc60318433;path=/;HttpOnly;Max-Age=1800
Server: nginx

这里,你会发现,在返回的字节头中根本没有ContenLength,所以最终解决办法是在下载之前的一个通讯中,让服务端返回要下载文件的总大小,然后你再去进行下载。

三. 优化下载的调用方式

最后,让我们来看看优化后RetroHttp关于下载的代码调用吧:

    /**更新apk**/
    private void updateApk(String url){
        String fileName= DownLoadHelper.getInstance().getDefaultFileName(url);
        RetroLog.i("=========fileName===kk==="+fileName);
        //启动下载
        DownLoadHelper.getInstance().setFileName(fileName)//设置下载文件名
                .setFileLength(10000)//设置下载文件大小
                .setIcon(R.mipmap.ic_launcher)//设置apk图标资源id
                .setAuthorityTag("xxxx")//设置要与清单文件的 provider 中配置的authorities值一致
                .setIncrementUpdate(false)//是否开启增量更新(true:开启,false:关闭,此行代码不设置会默认全量更新)
                .setUseDefaultDownDialog(true)//开启默认下载进度dialog
                .downLoadFile(url, MainActivity.this, new DownLoadHelper.DownloadListener(){
                    @Override
                    public void onStart() {

                    }

                    @Override
                    public void update(int progress, boolean done) {

                    }

                    @Override
                    public void onCompleted() {
                        
                    }

                    @Override
                    public void onError(String err) {
                        RetroLog.i("=========下载失败=====" + err);
                        if (DownLoadHelper.getInstance().isDeltaFileFailed(err)) {
                            RetroLog.i("=========增量更新下载失败=====" + err);
                            //增量更新下载失败的逻辑(一般发rx通知出来,然后改全量更新)
                            //......
                            //由于使用非增量更新,故此处不做处理
                        } else {
                            RetroLog.i("=========全量更新下载失败=====" + err);
                            //全量更新下载失败的逻辑(一般提示退出app)

                        }
                    }
                });
    }

这里需要注意的是:

  • setFileLength(10000):是设置下载文件总大小,当不设置此属性的时候,系统会默认采用ContenLength来计算文件总大小
  • setIncrementUpdate(false):表示是否采用增量更新的方式下载,默认是不采用
  • setUseDefaultDownDialog(true):表示是否使用默认的下载进度框,true 表示使用,false 表示不使用。默认情况下为fasle,即只有我们声明为true时,才会加载默认下载进度框。当 setUseDefaultDownDialog(fasle)时,你可以自定义加载进度条,类似下面这样:
    /**更新apk**/
    private void updateApk(String url){
        String fileName= DownLoadHelper.getInstance().getDefaultFileName(url);
        RetroLog.i("=========fileName===kk==="+fileName);
        //自定义加载进度框
        MyProgressDialog dialog= new MyProgressDialog();
        dialog.show();
        //启动下载
        DownLoadHelper.getInstance().setFileName(fileName)//设置下载文件名
                //其他代码省略
                //......
                .setUseDefaultDownDialog(false)//禁用默认下载进度dialog
                .downLoadFile(url, MainActivity.this, new DownLoadHelper.DownloadListener(){
                    @Override
                    public void onStart() {

                    }

                    @Override
                    public void update(int progress, boolean done) {
                         //更新进度条
                         dialog.setProgress(progress);
                    }

                    @Override
                    public void onCompleted() {
                         //进度条隐藏
                         dialog.dismiss();
                    }

                    @Override
                    public void onError(String err) {
                         //进度条隐藏
                         dialog.dismiss();

                        RetroLog.i("=========下载失败=====" + err);
                        if (DownLoadHelper.getInstance().isDeltaFileFailed(err)) {
                            RetroLog.i("=========增量更新下载失败=====" + err);
                            //增量更新下载失败的逻辑(一般发rx通知出来,然后改全量更新)
                            //......
                            //由于使用非增量更新,故此处不做处理
                        } else {
                            RetroLog.i("=========全量更新下载失败=====" + err);
                            //全量更新下载失败的逻辑(一般提示退出app)

                        }
                    }
                });
    }

ok,今天的内容就介绍到这里了,谢谢大家。

相关文章

网友评论

      本文标题:RetroHttp(六) — 下载进度

      本文链接:https://www.haomeiwen.com/subject/gvldkltx.html