RetroHttp(六) — 下载进度

前言

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,今天的内容就介绍到这里了,谢谢大家。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容