Android 图片加载框架 Glide ImageLoader,Picasso,Fresco

现在Android开发人员加载图片大多数用的是Glide 的吧。关于Glide ImageLoader,Picasso,Fresco有什么不对的请指正

一 、Glide介绍

GitHub:https://github.com/bumptech/glide

优势:

       1)使用简单

        2)可配置度高,自适应程度高

        3)支持常见图片格式jpg、png、gif、webp等

        4)支持多种数据源(网络、本地、资源、Assets等)

        5)高缓存策略 支持Memory和Disk图片缓存 默认Bitmap格式采用RGB_565内存使用至少减少一半( Picasso默认采用ARGB_8888)  内存上减少一半。

        6)声明周期集成,根据Activity/Fragment生命周期自动管理请求

        7)高效处理Bitmap,使用Bitmap Pool 使Bitmap复用,主动调用recycle回收需要回收的Bitmap,减少系统回收压力等。

重要功能:  

         (1)禁止内存缓存:skipMemoryCache(true)
         (2)清除内存缓存:Glide.get(context).clearMemory()  注:必须在UI线程中调用。
         (3)禁止磁盘缓存:.diskCacheStrategy(DiskCacheStrategy.NONE)
         (4)清除磁盘缓存:Glide.get(applicationContext).clearDiskCache()  注:必须在后台线程中调用。建议同时使用            clearMemory()
         (5)获取缓存大小:new GetDiskCacheSizeTask().execute(new File(context.getCacheDir(),DiskCache.Factory.DEFAULT_DISK_CACHE_DIR));

         (6)指定资源的优先加载顺序:priority() 依次递增: Priority.LOW、 Priority.NORMAL、 Priority.HIGH、 Priority.IMMEDIATE
         (7)先显示缩略图,再显示原图
         (8)对图片进行裁剪、模糊、过滤等处理(变换: https://github.com/wasabeef/glide-transformations  (滤镜、裁剪等))
         (9)对请求状态进行监听
         (10)对资源的下载进度进行监听等

Glide默认采用的事HttpUrlConnection来做网络请求的,如果想换成自己想用的网络请求,创建一个类,继承AppGlideModule在重写的registerComponents()方法中切换网络请求

如图:

Android 图片加载框架 Glide ImageLoader,Picasso,Fresco

Glide和RecyclerView使用想只在停止滑动时才加载图片可以这样使用:

RecycleView的 onScrollStateChanged 几种状态
  SCROLL_STATE_IDLE 屏幕停止滚动
  SCROLL_STATE_DRAGGING 屏幕滚动且用户使用的触碰或手指还在屏幕上
  SCROLL_STATE_SETTLING 由于用户的操作,屏幕产生惯性滑动
Gilde同时也为我们提供了两个方法
   resumeRequests() 开始加载图片
   pauseRequests() 停止加载
 

郭霖大神的关于Glide的解析系列https://blog.csdn.net/guolin_blog/article/details/53759439
面试官:简历上最好不要写Glide,不是问源码那么简单:https://juejin.im/post/5dbeda27e51d452a161e00c8#heading-21
 
二 、ImageLaoder介绍
 
 
设计及优势
 
Android 图片加载框架 Glide ImageLoader,Picasso,Fresco

设计流程:

    ImageLoader收到展示和加载图片的任务,并交给ImageLoaderEngine(创建任务,并进行任务调度)分配到具体的线程池去完成,任务通过 Cache (本地缓存)及 ImageDownloader (从网络获取图片)获取图片,中间可能经过 BitmapProcessor(图片处理器) 和 ImageDecoder (图片解码)处理,最终转换为Bitmap 交给 BitmapDisplayer 在 ImageAware 中显示。

   注:其中 Cache 分为 MemoryCache(内存缓存) 和 DiskCache(硬盘缓存) 两部分。

优势

1.多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
2.支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
3.支持图片的内存缓存,文件系统缓存或者SD卡缓存
4.支持图片下载过程的监听
5.根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
6.较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加        载图片,停止滑动的时候去加载图片
7.提供在较慢的网络下对图片进行加载
8.默认实现多种内存缓存算法 这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大     先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。

内存溢出OOM解决办法

    1.减少线程池中的个数:在ImageLoaderConfiguration中的(threadPoolSize)中配置,推荐配置1-5个。
    2.在DisplayImageOptions选项中配置bitmapConfig为Bitmap_Config_RGB_565 默认是RGB_8888,使用RGB_565比
RGB_8888少消耗2倍内存。
    3.在ImageLoaderConfiguration中配置图片的内存缓存为memoryCache(new WeakMemoryCache)(弱引用)或不使用内存
缓存。
    4. 设置加载图片的类型。 在DisplayImageOptions选项中配置设置.ImageScaleType(ImageScaleType.IN_SAMPLE_INT)
或者.ImageScaleType(ImageScaleType.EXACTLY) 。

三 、Picasso介绍
 
 
设计与优势
 
Android 图片加载框架 Glide ImageLoader,Picasso,Fresco

 Picasso 收到加载及显示图片的任务,创建 Request 并将它交给 Dispatcher,Dispatcher 分发任务到具体 RequestHandler,任务通过 MemoryCache 及 Handler(数据获取接口) 获取图片,图片获取成功后通过 PicassoDrawable 显示到 Target 中。

注:Dispatcher 负责分发和处理 Action,包括提交、暂停、继续、取消、网络状态变化、重试等等。

优势:

           1.在Adapter中取消了不在视图范围内的ImageView的资源加载,因为可能会产生图片错位;
           2.使用复杂的图片转换技术降低内存的使用
           3.自带内存和硬盘的二级缓存机制

缺点:

        1.Picasso.with(这里只能传入上下文)   
        2.Picasso采用的ARGB-8888
        3.Picasso不能加载git图片
        4.Picasso缓存的是全尺寸

四、 Fresco介绍
 
 

优点
1)内存自动回收。图片不可见时,会及时自动释放所占用的内存,尽可能地避免OOM( 在更底层的Native层对OOM进行)
2)三级缓存机制。两级内存缓存(解码的与未解码的)+一级磁盘缓存,提升加载速度,节省内存占用空间
3)支持各种加载场景。如动图加载、高斯模糊等常见的图片加载场景。另外还提供了独特的渐进式加载、先加载小图再加载大图,加载进度等功能(很强大)。

最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)
大大减少OOM(在更底层的Native层对OOM进行处理,图片将不再占用App的内存)
适用于需要高性能加载大量图片的场景


缺点
1)体积大(很胖)。较其他主流图片库体积要大不少
2)侵入性较强。须使用它提供的SimpleDraweeView来代替ImageView加载显示图片
综合来说,如果你的应用对图片的显示、加载等要求高的话,那就建议使用Fresco。但如果要求没那么高的话就用Glide或其它库吧。

特点
1.内存管理:内存分配采用:系统匿名共享内存(Ashmem区)(在更底层的Native层对OOM进行,别的框架采用是Java内存)
                    在5.0系统以下,将图片放到一个特别的内存区域,图片不显示的时候,占用的内存会自动被释放,使得APP更加流                            畅,减少因图片内存占用而引发OOM.
2.渐进式呈现图片:渐进式图片格式先呈现大致图片轮廓,然后随着图片的下载,呈现逐渐清晰的图片,这对于移动设备,尤其是慢                                  网络有极大的好处,可带来更好的用户体验。
3.支持加载GIF图,支持WebP格式
4.图像的呈现:①自定义居中焦点(人脸识别有好处)
                         ②圆角图,圆圈图等
                         ③下载失败之后,点击重新下载
                         ④自定义占位图,自定义overlay,或者进度条
                         ⑤指定用户按压时的overlay.
5.图片的加载: ①为同一个图片指定不同的远程路径,或者使用已经存在本地缓存中的图片
                          ②先显示一个低清晰度的图片,等高清图下载完成之后再显示高清图
                          ③加载完成回调通知
                          ④对于本地图,如有EXIF缩略图,在大图加载完成之前,可先显示缩略图
                          ⑤缩放或者旋转图片
                          ⑥处理已下载图片(对已下载完成图片进行进一步下载、封装)

支持URI格式:注Fresco 不支持 相对路径的URI. 所有的 URI 都必须是绝对路径,并且带上该 URI 的 scheme

类型

scheme

示例

远程图片

http://, https://

HttpURLConnection

本地文件

file://

 FileInputStream

Content provider

content://

ContentResolver

asset目录下的资源

content://

AssetManager

res目录下的资源

 res://   

Resources.openRawResource

res目录下的资源

data:mime/type;base64,

数据类型必须符合 rfc2397规定 (仅支持 UTF-8)

注意事项:( https://www.fresco-cn.org/docs/troubleshooting.html
1重复的边界
2图片没有加载
3文件不可用
4OOM - 无法分配图片空间
5Bitmap太大导致无法绘制
6通过Logcat来判断原因
7启动日志
8查看日志

陷阱:( https://www.fresco-cn.org/docs/gotchas.html
1不要使用 ScrollViews
2不要向下转换
3不要使用getTopLevelDrawable
4不要复用 DraweeHierarchies
5不要在多个DraweeHierarchy中使用同一个Drawable
6不要直接控制 hierarchy
7不要直接给 DraweeView 设置图片。
8使用 DraweeView 时,请不要使用任何 ImageView 的属性

wrap_content的限制( https://www.fresco-cn.org/docs/wrap-content.html

主要的原因是,Drawee永远会在getIntrinsicHeight/getIntrinsicWidth中返回-1。

这么做的原因是 Drawee 不像ImageView一样。它同一时刻可能会显示多个元素。比如在从占位图渐变到目标图时,两张图会有同时显示的时候。再比如可能有多张目标图片(低清晰度、高清晰度两张)。如果这些图像都是不同的尺寸,那么很难定义”intrinsic”尺寸。

如果我们要先用占位图的尺寸,等加载完成后再使用真实图的尺寸,那么图片很可能显示错误。它可能会被根据占位图的尺寸来缩放、裁剪。唯一防止这种事情的方式就只有在图片加载完成后强制触发一次layout。这样的话不仅会影响性能,而且会让应用的界面突变,很影响用户体验!如果用户正在读一篇文章,然后在图片加载完成后整篇文章突然向下移动,这是非常不好的。

所以你必须指定尺寸或者用match_parent来布局。

你如果从服务端请求图片,服务端可以做到返回图片尺寸。然后你拿到之后通过setLayoutParams 来给View设置宽高

共享元素动画( https://www.fresco-cn.org/docs/shared-transitions.html

使用它,因为Drawee维护着自己的转换Matrix。

幸运的是你可以有另一种做法:使用ChangeBounds。你可以改变layout的边界,这样Fresco会根据它进行自适应,也能够达到你想要的功能。 ChangeBounds,而不是ChangeImageTransform
Android 5.0 (Lollipop) 引入了 共享元素动画,允许在多个Activity切换时共享相同的View!

你可以在XML中定义这个变换。有个ChangeImageTransform变换可以在共享元素切换时对ImageView进行变换,可惜Fresco暂时不支持。