Glide原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangzihan91/article/details/85318064

1、基础知识

如何把图片解析成Bitmap:当ImageView可展示的像素点小于图片的像素点,这时我们就需要压缩图片,避免浪费内存空间。BitmapFactory类提供了多个解析方法(decodeByteArray, decodeFile, decodeResource等)用于创建Bitmap对象,而且每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值,在计算压缩比例时,我们要考虑加载控件的大小和屏幕的大小,通过设置BitmapFactory.Options中inSampleSize的值就可以压缩图片

图片缩放:ScaleType分为三个类型:以FIT_开头的四种,共同点都是会对图片进行缩放;以CENTER_开头的三种,共同点是图片的中心会与ImageView的中心点重叠;还有一种是ScaleType.MATRIX

ScaleType.FIT_CENTER:图片会被等比例缩放到能完全展示出来,并居中显示,图片默认显示模式

ScaleType.FIT_START:图片会被等比例缩放到能完全展示出来,对齐方式为左上角

ScaleType.FIT_END:图片会被等比例缩放到能完全展示出来,对齐方式为右下角

ScaleType.FIT_XY:非等比例缩放,完全填充控件大小

ScaleType.CENTER:不使用缩放,居中显示

ScaleType.CENTER_CROP:等比例缩放至完全填充整个ImageView,并居中显示,小图片不进行缩放

ScaleType.CENTER_INSIDE:等比例缩放至完全展示出整个图片,并居中显示,小图片不进行缩放

ScaleType.MATRIX:忽略

2、Glide简介

dependencies {
    compile 'com.github.bumptech.glide:glide:3.5.2' 
    compile 'com.android.support:support-v4:22.0.0'
}
Glide.with(context).load("http://inthecheesefactory.com/uploads/cover.jpg").into(ivImg);

与Picasso相比,Glide的with方法不仅接收Context,还接收Activity和Fragment,同时图片加载和Activity、Fragment的生命周期保持一致,比如在Paused状态暂停加载,在Resumed的时候自动重新加载

Glide默认Bitmap格式是RGB_565,Picasso默认Bitmap格式是ARGB_8888

Glide内存开销小于Picasso,原因是Picasso加载了全尺寸的图片到内存,然后让GPU来实时重绘大小,而Glide加载的大小和ImageView的大小是一致的,当然,Picasso也可以指定加载的图片大小:

Picasso.with(this).load("http://nuuneoi.com/cover.jpg").resize(768, 432).into(ivImgPicasso);

但问题在于我们需要计算ImageView的大小,或者说ImageView大小是具体的值(而不是wrap_content),我们也可以这样:

Picasso.with(this).load("http://nuuneoi.com/cover.jpg").fit().into(ivImgPicasso);

Picasso和Glide在磁盘缓存策略上有很大的不同。Picasso缓存的是全尺寸的,而Glide缓存的是跟ImageView尺寸相同的,具体说来就是:假如在第一个页面有一个200x200的ImageView,在第二个页面有一个100x100的ImageView,这两个ImageView本来是要显示同一张图片,却需要下载两次,不过,你可以改变这种行为,让Glide既缓存全尺寸又缓存其他尺寸:

Glide.with(this).load("http://nuuneoi.com/cover.jpg").diskCacheStrategy(DiskCacheStrategy.ALL).into(ivImg);

下次在任何ImageView中加载图片的时候,全尺寸的图片将从缓存中取出,重新调整大小,然后缓存。

Glide的这种方式优点是加载显示非常快,而Picasso的方式则因为需要在显示之前重新调整大小而导致一些延迟

Glide可以加载GIF动态图,而Picasso不能,但是从我的一次测试结果来看Glide 动画会消费太多的内存,因此谨慎使用

3、Glide原理:

with方法:with有很多重载方法,接收参数包括Context、Actitity、FragmentActivity、Fragment等,with方法内部主要处理生命周期相关,并返回RequestManager,我们重点分析生命周期:对于ApplicationContext,直接声明ApplicationLifecycle,并把RequestManager加入到Lifecycle的listener中,其实ApplicationLifeCycle什么都没做,甚至没有存储listeners。对于Activity和Fragment,Glide自动创建了一个Fragment,并把Fragment加入到了Activity中,并把RequestManager加入到Fragment控制的LifeCycle中,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了

load方法:该方法返回一个DrawableTypeRequest对象,父类是GenericRequestBuilder,里面包括Glide绝大多数API,比如说placeholder、error、diskCacheStrategy等

into方法:主要处理流程都在into中,我们重点分析缓存策略:首先,生成缓存Key的参数有10多个(包括id、width、height等)。在内存缓存策略中,我们通过弱引用来缓存正在使用的图片,通过LruCache(Least Recently Used)来缓存不在使用的图片。在硬盘缓存策略中,缓存分为两级,首先我们通过key值访问转换后的结果(RESULT),如果不存在,再通过简化的key值访问原始图片(SOURCE)

4、Picasso、Glide、Fresco对比

Picasso不能加载Gif图片、只能缓存全尺寸的图片,加载效率低、包体积小(100K)

Glide支持生命周期管理、自动裁剪图片、三级缓存、Gif图加载、包体积适中(500K)

Fresco支持5.0一下Ashmem区存储、包体积大(2M)

Fresco在5.0以前使用inPurgeable选项来解码Bitmap,这样解码出来的Bitmap是在Ashmem内存中,GC无法自动回收它。当该Bitmap在被使用时会被pin住,使用完之后就unpin ,这样系统就可以在将来某一时间释放这部分内存。如果一个unpinned的bitmap在之后又要被使用,系统会运行时又将它重新decode,但是这个decode操作是发生在UI线程中的有可能会造成掉帧现象,因此该做法已经被Google废弃掉,转为鼓励使用inBitmap来告知

为了让inPurgeable的bitmap不被自动unpinned,可以通过使用 jni 函数AndroidBitmap_lockPixels()函数来强制pin bitmap,这样我们就可以在bitmap被使用时不会被系统自动unpinned,从而也就避免了unpinned 的 bitmap在重新被使用时又会被重新decode而引起的掉帧问题。这做后,Fresco需要自己去管理这块内存区域,保证当这个Bitmap不再使用时,Ashmem的内存空间能被 unpin,Fresco选择在Bitmap离开屏幕可视范围时候(onDetachWindow等时候),通过调用bitmap.recycle()方法去做unpin

猜你喜欢

转载自blog.csdn.net/wangzihan91/article/details/85318064