前面我们已经讲解了老牌图片加载框架Universal-Image-Loader,讲解了它的使用,并分别从图片三级缓存的角度和缓存Lru算法角度详细分析了源码,还给大家做出了总结,不清楚的可以去 安卓面试系列–Universal-Image-Loader图片加载框架和 安卓面试系列–OOM异常(二)这两篇博客中看看。今天我们来讲另外两个图片加载框架,Picasso和Glide,这两者非常像,所以我们放在一起讲。
Picasso:
compile 'com.squareup.picasso:picasso:2.5.1'
Glide:
compile 'com.github.bumptech.glide:glide:3.5.2'
Picasso:
Picasso.with(context)
.load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
.into(ivImg);
Glide:
Glide.with(context)
.load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
.into(ivImg);
虽然两者看起来一样,但是Glide更易用,因为Glide的with方法不光接受Context,还接受Activity 和 Fragment,Context会自动的从他们获取。
将Activity或者Fragment作为with()的参数的好处是:图片加载会和Activity/Fragment的生命周期保持一致。比如在pause状态停止加载,在resume状态重新加载。所以建议把activity或者fragment作为参数传递给Glide,而不是Context。
Glide加载图片默认使用的是RGB_565,占用两个字节,而Picasso加载图片默认是加载完整的图,使用的是ARGB_8888,占用四个字节,所以,使用Glide消耗的内存比Picasso小一半,这也是Glide的一大优势所在。
这是把一张1920x1080 像素的图片加载到768x432的ImageView中,两者的内存开销对比图:
当然也不是说Glide不可以使用ARGB_8888格式加载图片,如果需要的话,可以新建一个GlideModule,然后在applyOptions中设置解码格式:
public class GlideConfiguration implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
// Apply options to the builder here.
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}
@Override
public void registerComponents(Context context, Glide glide) {
// register ModelLoaders here.
}
}
同时需要在manifest.xml文件中,将GlideModule定义为meta-data:
"com.inthecheesefactory.lab.glidepicasso.GlideConfiguration"
android:value="GlideModule"/>
我们可以发现,Glide花费的内存是上一次的两倍,但还是比Picasso小的多,为什么会这样呢?因为Picasso是把全尺寸的图片加载到内存中去,而Glide只是把和ImageView大小的图片加载到内存中去,所以更小。当然,Picasso也可以指定大小,通过resize()方法指定大小:
Picasso.with(this)
.load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")
.resize(768, 432)
.into(ivImgPicasso);
如果指定大小的话,那么你就需要准确的知道你的ImageView控件的大小,这可能会需要用到计算。但是你也可以这样:
Picasso.with(this)
.load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")
.fit()
.centerCrop()
.into(ivImgPicasso);
这样也可以实现加载控件大小的图片到内存。
这样Picasso的内存开销就和Glide差不多了。但是是不是比Glide麻烦多了,所以,在内存方面,Glide完胜。
Picasso和Glide在磁盘缓存上的策略大不相同。Picasso是缓存全尺寸到内存,而Glide则缓存和ImageView大小相同的尺寸到内存。
我们通过改变ImageView的尺寸来尝试分析两者缓存的不同,测试后发现,不管ImageView有多大,Picasso都只缓存一张全尺寸的图片到内存,而Glide则不同,每次都会缓存一张跟ImageView一样大的图片。假如我们继续改变ImageView的尺寸,Glide会重新下载这张图片,然后调整大小并缓存起来。
举个栗子:假如第一个页面是一个200*200的ImageView,第二个页面是100*100的ImageView,而这两个ImageView要显示的是一张图片,但是却要下载两次。
不过,我们通过以下设置,让Glide也缓存全尺寸的图片。
Glide.with(this)
.load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivImgGlide);
这样,下次不管ImageView有多大,我们都会把全尺寸的图片从缓存中取出来,然后调整大小并显示到ImageView上,并把这个尺寸的图片缓存起来,也就是说少了一次下载的过程。
Glide的这种方式的优点就是加载速度非常快,而Picasso则需要在显示之前重新调整大小而导致延时。
Glide可以做到和Picasso一样多的事情,代码量也不会增加太多。
// Picasso
.resize(300, 200);
// Glide
.override(300, 200);
// Picasso
.centerCrop();
// Glide
.centerCrop();
// Picasso
.transform(new CircleTransform())
// Glide
.transform(new CircleTransform(context))
// Picasso
.placeholder(R.drawable.placeholder)
.error(R.drawable.imagenotfound)
// Glide
.placeholder(R.drawable.placeholder)
.error(R.drawable.imagenotfound)
那么有什么是Glide独有的特性呢?
Glide可以加载动态图,而Picasso不可以
同时因为Glide和activity或者fragment的生命周期一致,所以gif动画也会随着activity或者fragment的状态暂停、重放。Glide的缓存在gif图中也是一样的,先调整大小然后在缓存。
但是Glide动画消耗的内存太多,需要谨慎使用。
除了可以加载gif动画,Glide还可以将本地视频解码成一张静态图片。
Glide还可以配置显示图片的动画,而Picasso只有fading in。