为Android图片加载添加百分比进度条(Picasso+Okhttp3)

本文介绍了如何在Android项目中利用Picasso和Okhttp3为图片加载添加进度条。通过创建单例的Picasso和Downloader,并在Okhttp3的拦截器中获取下载进度,实现了内存友好的图片加载。注意,获取进度需要服务器在响应头中包含"Content-Length"。文中还提到了防止ListView复用引起的进度错乱问题,以及Picasso和Okhttp3配合时可能出现的下载线程过多的情况。
摘要由CSDN通过智能技术生成

  前言

我目前工作的项目使用的是Android 的第三方图片加载库Picasso,最近有需求要为图片添加下载进度条,并准确提示下载进度。然而Picasso原生并不支持下载进度的回调(Fresco原生支持),但是Picasso好在灵活性还可以,能够自由的指定Downloader,于是我在原来使用Okhttp3 Http请求库的基础上添加了下载进度的提示,和网上其他的Picasso添加进度的方案不同,网上的都是生成多个Picasso实例和Downloader实例,导致Lru缓存失效和内存溢出的问题,我在实现中使用了单例Picasoo和Downloader,通过给OkhttpClient类添加拦截器的方式实现下载进度的回调,通过url进行分发,实现在ListView等控件中多图、省内存、防OOM的加载。

注:要实现进度的获取需要图片服务器在图片的Http响应头添加”Content-Length“

  实现效果

     

Github项目地址:https://github.com/AlexZhuo/AlxPicassoProgress


  实现思路

1、关于进度获取:

这里获取进度百分比的原理是通过请求图片的URL,获得Http响应报文后,从Header中获取到Content-Length获得文件的总大小,然后通过Okhttp3 的client获得当前读取的字节数,通过当前读取字节数除以Content-Length获得百分比。

2、关于Okhttp3和Picasoo的耦合:

Picasso默认不会自动使用Picasso,我通过重写了Picasso的Downloader添加了Picasso对Okhttp3的支持,具体实现可以看我之前的一篇博客:使用okhttp3做Android图片框架Picasso的下载器和缓存器

在那篇博客里面,我已经添加了一个拦截器,用来在手机Flash存储上存储下载好的图片,并设置过期时间为7天,今天这个issue我又添加了一个拦截器,用于获取当前文件的Content-Length和下载字节数,然后通过一个ProgressListener接口实现下载进度的回调,回调后通过url判断是哪个图片,然后控制圆形进度条控件和TextView显示进度。

3、关于圆形进度条控件:

这里我使用的是Github上的一个项目,github上关于进度条的自定义控件有很多,可以去找找有没有你爱用的,然后修改我这个Demo的控制进度条的相关代码就好

4、关于Picasso和Okhttp3配合的bug(极为关键):

Picasso在网络请求上处理的并不好,比如一个子元素很多的listView,如果我在上半部分的图片没有加载完,我就使劲往下滑,然后再滑回最顶部,然后再迅速的滑到最底部,那么Picasso对一张照片就会调用好多线程去同时下载,意思就是Picasso已经抛弃的下载任务,Okhttp3还会继续下载,导致Okhttp3下载好了某张照片也是没有用的,因为Picasso抛弃之后,又开启了一次新下载,然后Okhttp3又要再下载一遍,这种情况往往要花两倍的时间和流量去下载一个照片,在我的Demo中,出现这种情况会输出Log,并且进度显示“99.11%”,由于是进行一次完整的第二次下载,所以“99.11%”这个进度可能保持的时间比较长才显示出图片,但是你如果上下划一划,重走getConvertView()方法,Picasoo会让Okhttp3读取下载成功的Flash缓存,这时就可以迅速显示

另外Picasso一次下载最多开4个线程,也就是说最多同时下载4个图片,如果有4张图片正在下载没有完成,那么你滑到listView的底部,底下的那些照片会等待那4张下载完后才开始下载,效率比较低。

5、关于ListView,RecyclerView,GridView中控件复用:众所周知ListView中相同item的控件是复用的,如果处理不好,那么进度就会到处乱闪,一会显示A图的进度,一会显示B图的进度,我的处理方式是将url和控件通过setTag进行绑定,在更新进度之前,首先检查要更新的url是否同View.getTag(id)一致,如果不一致则不去更新,每次执行ListView adapter的getConvertView()方法时给进度条setTag,这样在复用控件的环境中,就不会出现错乱的问题


  实现步骤

本方案为了能看的清晰,特地去昵图网找了几张大图当demo,但如果你的网速太快,那么进度条可能转瞬即逝

首先需要在项目中引用Picasso,Okhttp3,和一个圆形进度条的控件materialish-progress,如下

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp3:okhttp:3.1.1'
    compile 'com.pnikosis:materialish-progress:1.7'

}

为了让Picasso支持Okhttp3,需要自定义一个Okhttp3的downloader,并在这个Downloader中添加获取下载字节数的拦截器,代码如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值