精华内容
下载资源
问答
  • 安卓 图片加载框架

    2014-11-11 11:17:40
    安卓 图片加载框架 包括列表 网格布局 画廊等加载网络图片数据 比较流畅的 现在分享给大家!
  • 1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存, 所以, 应用程序有更多的内存使用,不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收Bitmap导致...

    转自 http://www.csdn.net/article/2015-10-21/2825984【CSDN现场报道】10月14日-16日,“ 2015移动开发者大会 · 中国”(Mobile Developer Conference China 2015,简称MDCC 2015)在北京新云南皇冠假日酒店隆重举行。本次大会由全球最大中文IT社区CSDN和中国最具关注度的全方位创业平台创新工场联合主办,以“万物互联,移动为先”为主题,邀请国内外业界领袖与技术专家共论移动开发的热点,在实践中剖析技术方案与趋势。

    http://blog.csdn.net/wenyiqingnianiii/article/details/53045528  这篇主讲 毕加索和glide的区别

    快的打车移动端架构师 吴更新(Trinea) 

    这是快的打车移动端架构师、Android 开源项目源码解析 codeKK 发起人 吴更新( @Trinea)在MDCC上分享的内容(略微改动),也是源码解析第一期发布时介绍的源码解析后续会慢慢做的事。从总体设计和原理上对几个图片缓存进行对比,没用到它们的朋友也可以了解它们在某些特性上的实现。(PPT下载地址>>Android开源项目选型之图片缓存

    上篇关于选择开源项目的好处及如何选择开源项目可见: 开源项目使用及选型

    一. 四大图片缓存基本信息

    Universal ImageLoader 是很早开源的图片缓存,在早期被很多应用使用。

    Picasso 是 Square 开源的项目,且他的主导者是 JakeWharton,所以广为人知。

    Glide 是 Google 员工的开源项目,被一些 Google App 使用,在去年的 Google I/O 上被推荐,不过目前国内资料不多。

    Fresco 是 Facebook 在今年上半年开源的图片缓存,主要特点包括:

     

    1. 两个内存缓存加上 Native 缓存构成了三级缓存;
    2. 支持流式,可以类似网页上模糊渐进式显示图片;
    3. 对多帧动画图片支持更好,如 Gif、WebP。

     

    优点:

    1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存, 所以, 应用程序有更多的内存使用,不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收Bitmap导致的界面卡顿,性能更高.

    2. 渐进式加载JPEG图片, 支持图片从模糊到清晰加载

    3. 图片可以以任意的中心点显示在ImageView, 而不仅仅是图片的中心.

    4. JPEG图片改变大小也是在native进行的, 不是在虚拟机的堆内存, 同样减少OOM

    5. 很好的支持GIF图片的显示

    缺点:

    1. 框架较大, 影响Apk体积

    2. 使用较繁琐

     

     

    鉴于 Fresco 还没发布正式的 1.0 版本,同时一直没太多时间熟悉 Fresco 源码,后面对比不包括 Fresco,以后有时间再加入对比。

    二、基本概念

    在正式对比前,先了解几个图片缓存通用的概念:

     

    1. RequestManager:请求生成和管理模块;
    2. Engine:引擎部分,负责创建任务(获取数据),并调度执行;
    3. GetDataInterface:数据获取接口,负责从各个数据源获取数据。比如 MemoryCache 从内存缓存获取数据、DiskCache 从本地缓存获取数据,下载器从网络获取数据等。
    4. Displayer:资源(图片)显示器,用于显示或操作资源。 比如 ImageView,这几个图片缓存都不仅仅支持 ImageView,同时支持其他 View 以及虚拟的 Displayer 概念。
    5. Processor 资源(图片)处理器, 负责处理资源,比如旋转、压缩、截取等。

     

    以上概念的称呼在不同图片缓存中可能不同,比如 Displayer 在 ImageLoader 中叫做 ImageAware,在 Picasso 和 Glide 中叫做 Target。

    三、共同优点

    1. 使用简单 
    都可以通过一句代码可实现图片获取和显示。

    2. 可配置度高,自适应程度高 
    图片缓存的下载器(重试机制)、解码器、显示器、处理器、内存缓存、本地缓存、线程池、缓存算法等大都可轻松配置。

    自适应程度高,根据系统性能初始化缓存配置、系统信息变更后动态调整策略。 
    比如根据 CPU 核数确定最大并发数,根据可用内存确定内存缓存大小,网络状态变化时调整最大并发数等。

    3. 多级缓存 
    都至少有两级缓存、提高图片加载速度。

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

    5. 支持多种 Displayer 
    不仅仅支持 ImageView,同时支持其他 View 以及虚拟的 Displayer 概念。

    其他小的共同点包括支持动画、支持 transform 处理、获取 EXIF 信息等。

    四、ImageLoader 设计及优点

    1. 总体设计及流程

    上面是 ImageLoader 的总体设计图。整个库分为 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大模块,其中 Cache 分为 MemoryCache 和 DiskCache 两部分。

    简单的讲就是 ImageLoader 收到加载及显示图片的任务,并将它交给 ImageLoaderEngine,ImageLoaderEngine 分发任务到具体线程池去执行,任务通过 Cache 及 ImageDownloader 获取图片,中间可能经过 BitmapProcessor 和 ImageDecoder 处理,最终转换为Bitmap 交给 BitmapDisplayer 在 ImageAware 中显示。

    2. ImageLoader 优点

    (1) 支持下载进度监听

    (2) 可以在 View 滚动中暂停图片加载 
    通过 PauseOnScrollListener 接口可以在 View 滚动中暂停图片加载。

    (3) 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。

    (4) 支持本地缓存文件名规则定义

    缺点:

     缺点在于不支持GIF图片加载,  缓存机制没有和http的缓存很好的结合, 完全是自己的一套缓存机制

    五、Picasso 设计及优点

    1. 总体设计及流程

    上面是 Picasso 的总体设计图。整个库分为 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等模块。

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

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

    需要注意的是上面 Data 的 File system 部分,Picasso 没有自定义本地缓存的接口,默认使用 http 的本地缓存,API 9 以上使用 okhttp,以下使用 Urlconnection,所以如果需要自定义本地缓存就需要重定义 Downloader。

    2. Picasso 优点

    (1) 自带统计监控功能 
    支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。

    (2) 支持优先级处理 
    每次任务调度前会选择优先级高的任务,比如 App 页面中 Banner 的优先级高于 Icon 时就很适用。

    (3) 支持延迟到图片尺寸计算完成加载

    (4) 支持飞行模式、并发线程数根据网络类型而变 
    手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数,比如 wifi 最大并发为 4, 4g 为 3,3g 为 2。 
    这里 Picasso 根据网络类型来决定最大并发数,而不是 CPU 核数。

    (5) “无”本地缓存 
    无”本地缓存,不是说没有本地缓存,而是 Picasso 自己没有实现,交给了 Square 的另外一个网络库 okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。

    缺点

     

     于不支持GIF, 并且它可能是想让服务器去处理图片的缩放, 它缓存的图片是未缩放的, 并且默认使用ARGB_8888格式缓存图片, 缓存体积大.

     

    六、Glide 设计及优点

    1. 总体设计及流程

    上面是 Glide 的总体设计图。整个库分为 RequestManager(请求管理器),Engine(数据获取引擎)、Fetcher(数据获取器)、MemoryCache(内存缓存)、DiskLRUCache、Transformation(图片处理)、Encoder(本地缓存存储)、Registry(图片类型及解析器配置)、Target(目标)等模块。

    简单的讲就是 Glide 收到加载及显示资源的任务,创建 Request 并将它交给RequestManager,Request 启动 Engine 去数据源获取资源(通过 Fetcher ),获取到后 Transformation 处理后交给 Target。

    Glide 依赖于 DiskLRUCache、GifDecoder 等开源库去完成本地缓存和 Gif 图片解码工作。

    2. Glide 优点

    (1) 图片缓存->媒体缓存 
    Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video,所以更该当做一个媒体缓存。

    (2) 支持优先级处理

    (3) 与 Activity/Fragment 生命周期一致,支持 trimMemory 
    Glide 对每个 context 都保持一个 RequestManager,通过 FragmentTransaction 保持与 Activity/Fragment 生命周期一致,并且有对应的 trimMemory 接口实现可供调用。

    (4) 支持 okhttp、Volley 
    Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。

    (5) 内存友好 
    ① Glide 的内存缓存有个 active 的设计 
    从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。

    ② 内存缓存更小图片 
    Glide 以 url、viewwidth、viewheight、屏幕的分辨率等做为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小

    ③ 与 Activity/Fragment 生命周期一致,支持 trimMemory

    ④ 图片默认使用默认 RGB565 而不是 ARGB888 
    虽然清晰度差些,但图片更小,也可配置到 ARGB_888。

    其他:Glide 可以通过 signature 或不使用本地缓存支持 url 过期

    七、汇总

    三者总体上来说,ImageLoader 的功能以及代理容易理解长度都一般。

    Picasso 代码虽然只在一个包下,没有严格的包区分,但代码简单、逻辑清晰,一两个小时就能叫深入的了解完。

    Glide 功能强大,但代码量大、流转复杂。在较深掌握的情况下才推荐使用,免得出了问题难以下手解决。

    展开全文
  • 从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。...

    转自 http://www.csdn.net/article/2015-10-21/2825984【CSDN现场报道】10月14日-16日,“ 2015移动开发者大会 · 中国”(Mobile Developer Conference China 2015,简称MDCC 2015)在北京新云南皇冠假日酒店隆重举行。本次大会由全球最大中文IT社区CSDN和中国最具关注度的全方位创业平台创新工场联合主办,以“万物互联,移动为先”为主题,邀请国内外业界领袖与技术专家共论移动开发的热点,在实践中剖析技术方案与趋势。

    http://blog.csdn.net/wenyiqingnianiii/article/details/53045528  这篇主讲 毕加索和glide的区别

    快的打车移动端架构师 吴更新(Trinea)

    这是快的打车移动端架构师、Android 开源项目源码解析 codeKK 发起人 吴更新( @Trinea)在MDCC上分享的内容(略微改动),也是源码解析第一期发布时介绍的源码解析后续会慢慢做的事。从总体设计和原理上对几个图片缓存进行对比,没用到它们的朋友也可以了解它们在某些特性上的实现。(PPT下载地址>>Android开源项目选型之图片缓存

    上篇关于选择开源项目的好处及如何选择开源项目可见: 开源项目使用及选型

    一. 四大图片缓存基本信息

    Universal ImageLoader 是很早开源的图片缓存,在早期被很多应用使用。

    Picasso 是 Square 开源的项目,且他的主导者是 JakeWharton,所以广为人知。

    Glide 是 Google 员工的开源项目,被一些 Google App 使用,在去年的 Google I/O 上被推荐,不过目前国内资料不多。

    Fresco 是 Facebook 在今年上半年开源的图片缓存,主要特点包括:

    1. 两个内存缓存加上 Native 缓存构成了三级缓存;
    2. 支持流式,可以类似网页上模糊渐进式显示图片;
    3. 对多帧动画图片支持更好,如 Gif、WebP。

    优点:

    1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存, 所以, 应用程序有更多的内存使用,不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收Bitmap导致的界面卡顿,性能更高.

    2. 渐进式加载JPEG图片, 支持图片从模糊到清晰加载

    3. 图片可以以任意的中心点显示在ImageView, 而不仅仅是图片的中心.

    4. JPEG图片改变大小也是在native进行的, 不是在虚拟机的堆内存, 同样减少OOM

    5. 很好的支持GIF图片的显示

    缺点:

    1. 框架较大, 影响Apk体积

    2. 使用较繁琐


    鉴于 Fresco 还没发布正式的 1.0 版本,同时一直没太多时间熟悉 Fresco 源码,后面对比不包括 Fresco,以后有时间再加入对比。

    二、基本概念

    在正式对比前,先了解几个图片缓存通用的概念:

    1. RequestManager:请求生成和管理模块;
    2. Engine:引擎部分,负责创建任务(获取数据),并调度执行;
    3. GetDataInterface:数据获取接口,负责从各个数据源获取数据。比如 MemoryCache 从内存缓存获取数据、DiskCache 从本地缓存获取数据,下载器从网络获取数据等。
    4. Displayer:资源(图片)显示器,用于显示或操作资源。 比如 ImageView,这几个图片缓存都不仅仅支持 ImageView,同时支持其他 View 以及虚拟的 Displayer 概念。
    5. Processor 资源(图片)处理器, 负责处理资源,比如旋转、压缩、截取等。

    以上概念的称呼在不同图片缓存中可能不同,比如 Displayer 在 ImageLoader 中叫做 ImageAware,在 Picasso 和 Glide 中叫做 Target。

    三、共同优点

    1. 使用简单
    都可以通过一句代码可实现图片获取和显示。

    2. 可配置度高,自适应程度高
    图片缓存的下载器(重试机制)、解码器、显示器、处理器、内存缓存、本地缓存、线程池、缓存算法等大都可轻松配置。

    自适应程度高,根据系统性能初始化缓存配置、系统信息变更后动态调整策略。
    比如根据 CPU 核数确定最大并发数,根据可用内存确定内存缓存大小,网络状态变化时调整最大并发数等。

    3. 多级缓存
    都至少有两级缓存、提高图片加载速度。

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

    5. 支持多种 Displayer
    不仅仅支持 ImageView,同时支持其他 View 以及虚拟的 Displayer 概念。

    其他小的共同点包括支持动画、支持 transform 处理、获取 EXIF 信息等。

    四、ImageLoader 设计及优点


    1. 总体设计及流程

    上面是 ImageLoader 的总体设计图。整个库分为 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大模块,其中 Cache 分为 MemoryCache 和 DiskCache 两部分。

    简单的讲就是 ImageLoader 收到加载及显示图片的任务,并将它交给 ImageLoaderEngine,ImageLoaderEngine 分发任务到具体线程池去执行,任务通过 Cache 及 ImageDownloader 获取图片,中间可能经过 BitmapProcessor 和 ImageDecoder 处理,最终转换为Bitmap 交给 BitmapDisplayer 在 ImageAware 中显示。

    2. ImageLoader 优点

    (1) 支持下载进度监听

    (2) 可以在 View 滚动中暂停图片加载
    通过 PauseOnScrollListener 接口可以在 View 滚动中暂停图片加载。

    (3) 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。

    (4) 支持本地缓存文件名规则定义

    缺点:

     缺点在于不支持GIF图片加载,  缓存机制没有和http的缓存很好的结合, 完全是自己的一套缓存机制

    五、Picasso 设计及优点


    1. 总体设计及流程

    上面是 Picasso 的总体设计图。整个库分为 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等模块。

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

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

    需要注意的是上面 Data 的 File system 部分,Picasso 没有自定义本地缓存的接口,默认使用 http 的本地缓存,API 9 以上使用 okhttp,以下使用 Urlconnection,所以如果需要自定义本地缓存就需要重定义 Downloader。

    2. Picasso 优点

    (1) 自带统计监控功能
    支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。

    (2) 支持优先级处理
    每次任务调度前会选择优先级高的任务,比如 App 页面中 Banner 的优先级高于 Icon 时就很适用。

    (3) 支持延迟到图片尺寸计算完成加载

    (4) 支持飞行模式、并发线程数根据网络类型而变
    手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数,比如 wifi 最大并发为 4, 4g 为 3,3g 为 2。
    这里 Picasso 根据网络类型来决定最大并发数,而不是 CPU 核数。

    (5) “无”本地缓存
    无”本地缓存,不是说没有本地缓存,而是 Picasso 自己没有实现,交给了 Square 的另外一个网络库 okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。

    缺点

     于不支持GIF, 并且它可能是想让服务器去处理图片的缩放, 它缓存的图片是未缩放的, 并且默认使用ARGB_8888格式缓存图片, 缓存体积大.


    六、Glide 设计及优点


    1. 总体设计及流程

    上面是 Glide 的总体设计图。整个库分为 RequestManager(请求管理器),Engine(数据获取引擎)、Fetcher(数据获取器)、MemoryCache(内存缓存)、DiskLRUCache、Transformation(图片处理)、Encoder(本地缓存存储)、Registry(图片类型及解析器配置)、Target(目标)等模块。

    简单的讲就是 Glide 收到加载及显示资源的任务,创建 Request 并将它交给RequestManager,Request 启动 Engine 去数据源获取资源(通过 Fetcher ),获取到后 Transformation 处理后交给 Target。

    Glide 依赖于 DiskLRUCache、GifDecoder 等开源库去完成本地缓存和 Gif 图片解码工作。

    2. Glide 优点

    (1) 图片缓存->媒体缓存
    Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video,所以更该当做一个媒体缓存。

    (2) 支持优先级处理

    (3) 与 Activity/Fragment 生命周期一致,支持 trimMemory
    Glide 对每个 context 都保持一个 RequestManager,通过 FragmentTransaction 保持与 Activity/Fragment 生命周期一致,并且有对应的 trimMemory 接口实现可供调用。

    (4) 支持 okhttp、Volley
    Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。

    (5) 内存友好
    ① Glide 的内存缓存有个 active 的设计
    从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。

    ② 内存缓存更小图片
    Glide 以 url、viewwidth、viewheight、屏幕的分辨率等做为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小

    ③ 与 Activity/Fragment 生命周期一致,支持 trimMemory

    ④ 图片默认使用默认 RGB565 而不是 ARGB888
    虽然清晰度差些,但图片更小,也可配置到 ARGB_888。

    其他:Glide 可以通过 signature 或不使用本地缓存支持 url 过期

    七、汇总

    三者总体上来说,ImageLoader 的功能以及代理容易理解长度都一般。

    Picasso 代码虽然只在一个包下,没有严格的包区分,但代码简单、逻辑清晰,一两个小时就能叫深入的了解完。

    Glide 功能强大,但代码量大、流转复杂。在较深掌握的情况下才推荐使用,免得出了问题难以下手解决。

    展开全文
  • 做android的同学肯定都使用过imageloader这款图片加载框架。 图片加载对于中低级的安卓开发人员来说是相当不容易的,因为图片加载时做容易造成安卓内存溢出的原因,而要解决这些问题还需要很多相关知识: 1、多...

    做android的同学肯定都使用过imageloader这款图片加载框架。
    图片加载对于中低级的安卓开发人员来说是相当不容易的,因为图片加载时做容易造成安卓内存溢出的原因,而要解决这些问题还需要很多相关知识:
    1、多线程下载,线程管理。
    2、多级缓存架构设计和策略,内存缓存,磁盘缓存,缓存有效性处理。
    3、图片压缩,特效处理,动画处理。
    4、复杂网络情况下下载图片策略,例如弱网络等。
    5、内存管理,lru 算法、对象引用、GC回收等优化。
    等等一些功能都会是新手开发者摸不到头脑,而imageloader刚好把上述问题解决了,所以这款图片框架基本上成为了必备神框架一般存在。


    就想Android系统迭代速度一样快,这款框架团队已经到了没有再更新了时候了,取而代之是一些新的更加牛x的框架。
    现在主流的是:
    Glide:这个谷歌推荐的,肯定要放到第一个来说,相当于谷歌亲儿子,但是不是每个谷歌亲儿子都能够发展的很好,比如停止更新volley不想说了,现在用换成了okhttp成为新宠。
    首先项目非常轻巧,源代码体积小,功能齐全,使用api简单方便。还有就是出色图片处理,保存bitmap格式是RGB565,对内存消耗低。


    Fresco:刚好公司项目把imageloader转成fresco,名字挺好听壁画。
    在图片不显示他的内存会被回收。
    有模糊图片现加载,然后高清图片下载后再显示,类似预加载效果。
    图片动画处理非常丰富。
    但是项目源码体积大,但是现在都是巨型APP时代这个缺点也不算什么,只要功能强大就行。


    Picasso:这个框架和Glide的api非常类型,相似度有90%。bitmap保存格式是ARGB8888,所以对内存消耗没有Glide 出色。


    现在的主流三款框架都能够完成imageloader的功能而且还能够有更多强大的功能,但是开发就也发现不是功能越多越好,适合项目才是最好的,其实imageloader已经完成了基本上图片加载相关所有功能了。而且平时项目中没有什么特别的需求。


    所以还是默默的有点怀念它,只是不更新了,现在代码是自己默认imageloader写的一个阉割版的imageloader留作纪念。
    有点偷懒没有加入lrucache 二级缓存,就做了一级磁盘缓存,使用的asytask也是想调用时候少少传递上下文这个参数和线程管理,但是挺好用的呵呵!因为简单可以扩展和学习使用。


    使用方法:


    // 初始化默认最大宽度和保存文件夹 可以放到 application onCreate 方法中
    DisplayMetrics outMetrics=new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
    SimpleImageLoader.getInstance().init(outMetrics.widthPixels, Environment.getExternalStorageDirectory().getAbsolutePath()+"/sijienet_com");






    //默认调用
    SimpleImageLoader.getInstance().displayImage(imageUrls[position],imageView);






    //图片处理圆形图片
    SimpleImageLoader.getInstance().displayImage(imageUrls[position],imageView, new OnImageLoaderListener() {
    @Override
    public void setImageView(ImageView imageView,Bitmap bitmap) {
    imageView.setImageBitmap(SimpleImageLoader.getOvalBitmap(bitmap));
    }
    });


    //图片处理圆角图片
    SimpleImageLoader.getInstance().displayImage(imageUrls[position],imageView, new OnImageLoaderListener() {
    @Override
    public void setImageView(ImageView imageView,Bitmap bitmap) {
    imageView.setImageBitmap(SimpleImageLoader.getRoundedCornerBitmap(bitmap, 100));
    }
    });


    //设置获取bitmap大小,优先级高于默认最大宽度
    SimpleImageLoader.getInstance().displayImage(imageUrls[position],imageView, 250);




    //activity退出清除当前现在任务
    SimpleImageLoader.getInstance().cancelAllTasks();




    Simpleimageloader 代码:

    package com.net.sijienet.imageloader;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.lang.ref.WeakReference;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.security.MessageDigest;
    import java.util.ArrayList;
    import java.util.List;
    
    import android.annotation.SuppressLint;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.os.AsyncTask;
    import android.os.Environment;
    import android.util.Log;
    import android.widget.ImageView;
    
    /**
     * Created by json li on 2017/3/24. 
     * sijienet.com
     */
    @SuppressLint("NewApi") 
    public class SimpleImageLoader {
    
        public static SimpleImageLoader instance=null;
        
        private final String TAG="SimpleImageLoader";
    
        private List<LoadTask> loadTasks=new ArrayList<LoadTask>();
        
        private int defaultReqWidth;
        
        private String sdPath;
        
        public static SimpleImageLoader getInstance(){
            if (instance==null){
                synchronized (SimpleImageLoader.class){
                    if (instance==null){
                        instance=new SimpleImageLoader();
                    }
                }
            }
            return instance;
        }
        
        public void init(int defaultReqWitdth , String sdPath){
        	this.sdPath = sdPath;
        	this.defaultReqWidth = defaultReqWitdth;
        	Log.i(TAG, "max width="+defaultReqWitdth+" filePath="+sdPath);
        }
    
        private SimpleImageLoader(){
            defaultReqWidth = 750;
            sdPath=Environment.getExternalStorageDirectory().getAbsolutePath()+"/simple_imageloader_dir";
        }
    
        void setImgBitmap(ImageView imageView, Bitmap bitmap,OnImageLoaderListener imageLoaderListener){
        	if (imageLoaderListener!=null) {
    			imageLoaderListener.setImageView(imageView, bitmap);
    			return;
    		}
            imageView.setImageBitmap(bitmap);
        }
        
        public void displayImage(String url, ImageView imageView){
        	displayImage(url, imageView, defaultReqWidth, null);
        }
        
        public void displayImage(String url, ImageView imageView,OnImageLoaderListener imageLoaderListener){
        	displayImage(url, imageView, defaultReqWidth, imageLoaderListener);
        }
        
        public void displayImage(String url, ImageView imageView,int reqWidth){
        	displayImage(url, imageView, reqWidth, null);
        }
    
        public void displayImage(String url, ImageView imageView, int reqWidth, OnImageLoaderListener imageLoaderListener){
            if (url==null || imageView==null){
                return;
            }
            Bitmap bitmap=getBitmapFromCache(url, reqWidth);
            if (bitmap !=null){
                setImgBitmap(imageView, bitmap, imageLoaderListener);
            }else {
                LoadTask loadTask=new LoadTask(new WeakReference<ImageView>(imageView), url, reqWidth, imageLoaderListener);
                loadTasks.add(loadTask);
                loadTask.execute(url);
            }
        }
    
        public void cancelAllTasks() {
            if (loadTasks != null) {
                for (LoadTask task : loadTasks) {
                    task.cancel(false);
                }
                Log.i(TAG,"cancel size=="+ loadTasks.size());
                loadTasks.clear();
            }
        }
        
        String getAllPath(String url){
        	File file=new File(sdPath);
        	if (!file.exists()) {
    			file.mkdirs();
    		}
        	String fileName = getMd5String(url)+".jpg";
            String allPath = sdPath+"/"+fileName;
            return allPath;
        }
    
        public Bitmap getBitmapFromCache(String key, int reqWidth) {
            Bitmap bitmap=null;
            String allPath = getAllPath(key);
            if (new File(allPath).exists())
            {
                return decodeSampledBitmapFromResource(allPath, reqWidth);
            }
            return bitmap;
        }
    
        class LoadTask extends AsyncTask<String, Void, Bitmap> {
    
            WeakReference<ImageView> imageView;
            String url;
            int reqWidth;
            OnImageLoaderListener imageLoaderListener;
    
            public LoadTask(WeakReference<ImageView> imageView, String url,
    				int reqWidth, OnImageLoaderListener imageLoaderListener) {
    			super();
    			this.imageView = imageView;
    			this.url = url;
    			this.reqWidth = reqWidth;
    			this.imageLoaderListener = imageLoaderListener;
    		}
    
    		@Override
            protected Bitmap doInBackground(String... arg0) {
                Bitmap bitmap = downloadBitmap(url);
                return bitmap;
            }
    
            @Override
            protected void onPostExecute(Bitmap result) {
                super.onPostExecute(result);
                ImageView imageView = this.imageView.get();
                if (imageView != null && result != null) {
                    Log.i(TAG,"load imageView url=="+ url);
                    setImgBitmap(imageView, result, imageLoaderListener);
                }
                loadTasks.remove(this);
            }
    
            Bitmap downloadBitmap(String imageUrl) {
                Bitmap bitmap = null;
                HttpURLConnection con = null;
                FileOutputStream fileOutputStream=null;
                try {
                    URL url = new URL(imageUrl);
                    con = (HttpURLConnection) url.openConnection();
                    con.setConnectTimeout(2 * 1000);
                    con.setReadTimeout(10 * 1000);
                    con.setDoInput(true);
                    con.setDoOutput(true);
                    String allPath = getAllPath(this.url);
                    fileOutputStream=new FileOutputStream(allPath);
                    byte[] arr=new byte[1024];
                    int len=-1;
                    while( (len=con.getInputStream().read(arr))!=-1 ){
                        fileOutputStream.write(arr,0,len);
                    }
                    bitmap=decodeSampledBitmapFromResource(allPath, reqWidth);
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.i(TAG,"image load error=="+ e.getMessage());
                } finally {
                	if (fileOutputStream!=null) {
                		try {
                			fileOutputStream.flush();
        					fileOutputStream.close();
    					} catch (Exception e2) {
    						e2.printStackTrace();
    					}
    				}
                    if (con != null) {
                        con.disconnect();
                    }
                }
                return bitmap;
            }
    
        }
        
        public interface OnImageLoaderListener{
        	void setImageView(ImageView imageView, Bitmap bitmap);
        }
    
    
        public static String getMd5String(String str){
            StringBuilder sb = new StringBuilder(40);
            try {
                MessageDigest md5=MessageDigest.getInstance("MD5");
                byte[] bs = md5.digest(str.getBytes());
                for(byte x:bs) {
                    if((x & 0xff)>>4 == 0) {
                        sb.append("0").append(Integer.toHexString(x & 0xff));
                    } else {
                        sb.append(Integer.toHexString(x & 0xff));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return sb.toString();
        }
    
        public static Bitmap getRoundedCornerBitmap(Bitmap bitmap,float roundPx){
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
            final int color = 0xff424242;
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final RectF rectF = new RectF(rect);
            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(color);
            canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);
    
            return output;
        }
    
        public static Bitmap getOvalBitmap(Bitmap bitmap){
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
            final int color = 0xff424242;
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final RectF rectF = new RectF(rect);
            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(color);
            canvas.drawOval(rectF, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);
            return output;
        }
        
        public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth) {
            final int width = options.outWidth;
            int inSampleSize = 1;
            if (width > reqWidth) {
                final int widthRatio = Math.round((float) width / (float) reqWidth);
                inSampleSize = widthRatio;
            }
            return inSampleSize;
        }
    
        public static Bitmap decodeSampledBitmapFromResource(String pathName, int reqWidth) {
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(pathName, options);
            options.inSampleSize = calculateInSampleSize(options, reqWidth);
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(pathName, options);
        }
    
    
    }



    展开全文
  • Fresco 是Facebook开源的安卓上的图片加载框架,也可以说是至今为止安卓上最强大的图片加载框架. 相对于其他几个图片加载框架,Fresco主要的优点在于更好的内存管理和更强大的功能,更便捷的使用,缺点则是体积比较大,...

    简介

    Fresco 是Facebook开源的安卓上的图片加载框架,也可以说是至今为止安卓上最强大的图片加载框架.

    相对于其他几个图片加载框架,Fresco主要的优点在于更好的内存管理和更强大的功能,更便捷的使用,缺点则是体积比较大,引入后会导致应用apk增加1.5M到2M的大小,但是相对于其便捷性来讲,我觉得这都不是事儿.

    优点一:内存管理

    对于5.0以下系统,fresco使用”ashmem”(匿名共享内存)区域存储Bitmap缓存,这样Bitmap对象的创建、释放将不会触发GC,不会占用javaheap.这个特点是其他图片加载框架所没有做到的.

    5.0以上系统,由于安卓系统本身内存管理的优化,所以对于5.0以上的系统Fresco将Bitmap缓存直接放到了javaheap内存中.

    并且,fresco实现了真正的三级缓存:两级的内存缓存+一个磁盘缓存.两个内存缓存为:bitmap缓存 和未解码的图片缓存,这样既可以加快图片的加载速度,又能节省内存的占用.这个两级的内存缓存也是其他图片加载框架所没有做到的.

    另外提一点,在app切换到后台时,fresco会自动清理两级的内存缓存,无需手动.

    通过以上几点,使用fresco加载图片时内存占用要比其他图片加载框架小一大半,基本很少发生oom的事情.

    几个图片加载框架的内存占用测试结果对比请戳这里:Android Image Loader 第三方库对比测试

    优点二:更便捷的使用:

    初期入门,轻度的图片加载,甚至可以直接用:

    Fresco.initiliaze(context);
    
    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/my_image_view"
        android:layout_width="20dp"
        android:layout_height="20dp"
        fresco:placeholderImage="@drawable/news_default"
          .../>
    
    simpleDraweeView.setImageURI(uri);

    其他都不用管,fresco自动帮我们做缓存,图片缩略.

    显示圆角或圆圈图片也只是xml中配置一下而已:

    圆圈 - 设置roundAsCircle为true
    圆角 - 设置roundedCornerRadius

    另外再说一句,fresco还支持webp,所以,splash和引导界面的大图我一般都是用智图压成webp放在drawable中,用fresco加载就行了.

    相关文档及开源库

    官方文档中文版

    Github开源库:facebook/fresco,已更新到0.10.0

    中文的Fresco源码解读,分析版本:0.7.0

    fresco里的photoview :用于查看大图并随手势缩放

    bilibili开源的借助fresco加载图片的 spannable text view : Bilibili/drawee-text-view

    fresco的bitmap后处理器封装,可以直接使用,关于后处理请看文档

    使用心得及一些方法的封装

    加载超级大图还是会卡

    首先,终极的解决方法肯定是,客户端在图片请求中带上需要的宽和高,服务器将图片缩略到该规格后返回该小图.这个做得比较好的是七牛.

    注意:不管服务器能不能返回缩略图,所存储的原图都不应该太大,有时图片太大,甚至都无法下载下来(报504之类的错误).

    那么,如果服务器只能拿到原图或大图,fresco怎么缩略显示?

    fresco中提供了三个功能来生成缩略图:

    Scaling :画布操作,通常是由硬件加速的。图片实际大小保持不变,它只不过在绘制时被放大或缩小.使用时需要配置缩放类型fresco:actualImageScaleType,具体类型名与Imageview的ScaleType几乎一样.

    Resizing 是一种软件执行的管道操作。它返回一张新的,尺寸不同的图片,也就是说直接改变bitmap的大小,可惜是单独使用时,只支持jpg,当然,结合Downsampling使用时,可以支持除gif以为的所有常见图片,包括webp.

    Downsampling 同样是软件实现的管道操作。它不是创建一张新的图片,而是在解码时改变图片的大小。 同样是软件实现的管道操作。它不是创建一张新的图片,而是在解码时改变图片的大小。类似于android中的BitmapFactory在decodefile时的inSampleSize,都是指定一个采样率,默认是关闭的,如果开启,那么需要结合Resizing来使用.

    综上,要缩小内存占用,以及减少cpu计算量,减少卡顿,应该是Downsampling结合Resizing来使用.其中Downsampling是在Fresco初始化时开启,而Resizing则是通过构建ImageRequest时通过制定宽高来实现,所以可以定制每一张或每一类图片的宽高. 示例代码如下

    初始化:

      /**
         * 初始化操作,建议在子线程中进行
         * 添加的依赖:
         *  compile 'com.facebook.fresco:fresco:0.10.0+'
            compile 'com.facebook.fresco:animated-webp:0.10.0'//加载webp必须添加
            compile 'com.facebook.fresco:animated-gif:0.10.0' //加载gif必须添加
         * @param context
         * @param cacheSizeInM  磁盘缓存的大小,以M为单位
         */
        public static void init(final Context context,int cacheSizeInM){
    
    
            DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setMaxCacheSize(cacheSizeInM*1024*1024)//最大缓存
                    .setBaseDirectoryName(PHOTO_FRESCO)//子目录
                    .setBaseDirectoryPathSupplier(new Supplier<File>() {
                        @Override
                        public File get() {
                            return context.getCacheDir();//还是推荐缓存到应用本身的缓存文件夹,这样卸载时能自动清除,其他清理软件也能扫描出来
                        }
                    })
                    .build();
            MyImageCacheStatsTracker imageCacheStatsTracker = new MyImageCacheStatsTracker();//缓存的监听接口,其方法空实现即可
            ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context)
                    .setMainDiskCacheConfig(diskCacheConfig)
                    .setImageCacheStatsTracker(imageCacheStatsTracker)
                    .setDownsampleEnabled(true)
              //Downsampling,要不要向下采样,它处理图片的速度比常规的裁剪scaling更快,
              // 并且同时支持PNG,JPG以及WEP格式的图片,非常强大,与ResizeOptions配合使用
                    .setBitmapsConfig(Bitmap.Config.RGB_565)
              //如果不是重量级图片应用,就用这个省点内存吧.默认是RGB_888
                    .build();
            Fresco.initialize(context, config);
        }

    利用SimpleDraweeView加载图片的一般姿势:

    注意,我这里没有去设置DraweeHierarchy,因为依照fresco的设计思维,DraweeHierarchy属于view层次的东西,应该在xml中配置.当然如果非要设置,请看这里.

    public static void load(Uri uri,SimpleDraweeView draweeView,BasePostprocessor processor,int width,int height,
                                    BaseControllerListener listener){
            ImageRequest request =
                    ImageRequestBuilder.newBuilderWithSource(uri)
                            .setPostprocessor(processor)
                            .setResizeOptions(new ResizeOptions(width,height))
                            //缩放,在解码前修改内存中的图片大小, 配合Downsampling可以处理所有图片,否则只能处理jpg,
                            // 开启Downsampling:在初始化时设置.setDownsampleEnabled(true)
                            .setProgressiveRenderingEnabled(true)//支持图片渐进式加载
                            .setAutoRotateEnabled(true) //如果图片是侧着,可以自动旋转
                            .build();
    
            PipelineDraweeController controller =
                    (PipelineDraweeController) Fresco.newDraweeControllerBuilder()
                            .setImageRequest(request)
                            .setControllerListener(listener)
                            .setOldController(draweeView.getController())
                            .setAutoPlayAnimations(true) //自动播放gif动画
                            .build();
    
            draweeView.setController(controller);
        }

    显示图片时把人的头部给截掉了

    这个就要用到Scaling了.图片的缩放拉伸以及裁剪模式.具体看文档

    可用的缩放类型

    类型 描述
    center 居中,无缩放。
    centerCrop 保持宽高比缩小或放大,使得两边都大于或等于显示边界,且宽或高契合显示边界。居中显示。
    focusCrop 同centerCrop, 但居中点不是中点,而是指定的某个点。
    centerInside 缩放图片使两边都在显示边界内,居中显示。和 fitCenter 不同,不会对图片进行放大。如果图尺寸大于显示边界,则保持长宽比缩小图片。
    fitCenter 保持宽高比,缩小或者放大,使得图片完全显示在显示边界内,且宽或高契合显示边界。居中显示。
    fitStart 同上。但不居中,和显示边界左上对齐。
    fitEnd 同fitCenter, 但不居中,和显示边界右下对齐。
    fitXY 不保存宽高比,填充满显示边界。
    none 如要使用tile mode显示, 需要设置为none

    这些缩放类型和Android ImageView 支持的缩放类型几乎一样.

    图片默认是centerCrop,那么在用一个横向的SimpleDraweeView来显示一张竖着拍的人像时,就很可能把人的头部给截掉了,但对于在listview中展示的SimpleDraweeView来说,我们又无法用focusCrop直接指定其居中点在图片上半部分某个地方,因为其他图片可能是横着拍的或很正方形的自拍,这个时候怎么办?就需要根据人脸的检测来设置focusCrop的那个点了,而android从sdk 1.0开始就已经提供了一个人脸识别的类FaceDetector,原理是通过找眼睛来识别人脸,可以拿到眼睛的中心点坐标,那么根据该坐标,结合图片本身的宽高,计算出针对每张图片的focusCrop 需要设置的点,就能够解决这个问题了.

    //todo 这个还没有去写方法,但有一个开源项目facecropper可以参考,他们的做法是将一个大的bitmap截图成小的bitmap.同样的代码还有中文注释版的,汗…

    获取缓存的图片文件

    对于内存的缓存,fresco根据图片Uri,以及图片的resising参数和processor参数综合生成缓存key来缓存bitmap,而磁盘文件缓存则是只根据Uri生成key,那么,如果要获取文件缓存,只需要知道uri和通过key取file的api就行了,原先的调用链较长,故封装成单个方法:

    需要注意的是文件名后缀不是普通的图片后缀(.jpg之类的),而是.cnt,但都是二进制文件,可以将文件直接拷贝到指定路径重命名成正常图片后缀即可.当然如果只是读取到内存做其他用途,可以直接读取,无需拷贝更改后缀,不影响使用.

    以下是读取缓存文件的方法.而拷贝到其他文件目录的方法也已封装好于FrescoUtils中.

    public static File getFileFromDiskCache(String url){
            File localFile = null;
            if (!TextUtils.isEmpty(url)) {
                CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(url));
                if (ImagePipelineFactory.getInstance().getMainFileCache().hasKey(cacheKey)) {
                    BinaryResource resource = ImagePipelineFactory.getInstance().getMainFileCache().getResource(cacheKey);
                    localFile = ((FileBinaryResource) resource).getFile();
                } else if (ImagePipelineFactory.getInstance().getSmallImageFileCache().hasKey(cacheKey)) {
                    BinaryResource resource = ImagePipelineFactory.getInstance().getSmallImageFileCache().getResource(cacheKey);
                    localFile = ((FileBinaryResource) resource).getFile();
                }
            }
            return localFile;
        }
    
    

    如果我想用fresco来下载图片,不需要显示,要怎么实现?

    首先,如果是单纯的下载,建议使用专门的文件下载框架FileDownloader

    如果非要用fresco,那么需要绕一点弯:

    ​ 通过imagePipeline.prefetchToDiskCache将图片缓存到disk,然后拷贝出来.缓存完成的监听采用fresco提供的BaseDataSubscriber,在文件缓存完成后回调,然后拷贝文件到指定目录.

    注意:该方式不是很好用,偶尔会有失败的情况出现.

     /**
         * 文件下载到文件夹中:将图片缓存到本地后,将缓存的图片文件copy到另一个文件夹中
         *
         * 容易发生如下异常,progress在100处停留时间长
         * dalvikvm: Could not find method android.graphics.Bitmap.getAllocationByteCount,
         * referenced from method com.facebook.imageutils.BitmapUtil.getSizeInBytes
         06-21 16:15:39.547 3043-3244/com.hss01248.tools W/dalvikvm: VFY:
         unable to resolve virtual method 569: Landroid/graphics/Bitmap;.getAllocationByteCount ()I
    
         * @param url
         * @param context
         * @param dir 保存图片的文件夹
         * @param listener 自己定义的回调
         */
        public static void download(final String url, Context context, final File dir, final DownloadListener listener){
            ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
                    .build();
    
            final ImagePipeline imagePipeline = Fresco.getImagePipeline();
    
    
            DataSource<Void> dataSource = imagePipeline.prefetchToDiskCache(imageRequest, context, Priority.HIGH);
            dataSource.subscribe(new BaseDataSubscriber<Void>() {
                @Override
                protected void onNewResultImpl(DataSource<Void> dataSource) {
    
    
                  File  file  =   copyCacheFileToDir(url,dir);
                    clearCacheByUrl(url);//清除缓存
                    if (file == null || !file.exists()){
                        listener.onFail();
                    }else {
                        listener.onSuccess(file);
                    }
    
                }
    
                @Override
                public void onProgressUpdate(DataSource<Void> dataSource) {
                    super.onProgressUpdate(dataSource);
                    listener.onProgress(dataSource.getProgress());
                }
    
                @Override
                protected void onFailureImpl(DataSource<Void> dataSource) {
                    listener.onFail();
                }
            }, CallerThreadExecutor.getInstance());
    
        }
    

    由于某种原因无法使用SimpleDraweeView来显示图片(比如说弹幕上显示头像),而需要直接操作bitmap,那么要怎么拿到url返回的bitmap?

    自己构建图片请求,然后类似上面的文件下载,还是采用DataSubscriber来监听回调,只不过返回的不是void,而是CloseableImage的bitmap,

    /**
         * 拿到指定宽高,并经过Processor处理的bitmap
         * @param url
         * @param context
         * @param width
         * @param height
         * @param processor 后处理器,可为null
         * @param listener
         *
         */
        public static void getBitmapWithProcessor(String url, Context context, int width, int height,
                                                  BasePostprocessor processor,final BitmapListener listener){
    
            ResizeOptions resizeOptions = null;
            if (width !=0 && height != 0 ){
                resizeOptions = new ResizeOptions(width, height);
            }
    
            ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
                    .setProgressiveRenderingEnabled(false) 
              //我们是拿bitmap对象,不是显示,所以这里不需要渐进渲染
                    .setPostprocessor(processor)
                    .setResizeOptions(resizeOptions)
                    .build();
    
            ImagePipeline imagePipeline = Fresco.getImagePipeline();
    
            DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
            dataSource.subscribe(new BaseBitmapDataSubscriber() {
                @Override
                protected void onNewResultImpl(Bitmap bitmap) {
                    listener.onSuccess(bitmap);
                }
    
                @Override
                protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
                    listener.onFail();
                }
            }, CallerThreadExecutor.getInstance());
    
        }

    注意,此bitmap对象的缓存由Fresco管理,所以不要去调用bitmap.recycle()之类的方法.

    对此bitmap的一些处理,如果处理后的bitmap对象还是指向该bitmap引用,会影响到其他同样url,width height,并且同样Postprocessor的图片组件的显示,比如,将该bitmap高斯模糊了,就会影响到其他的这四个参数相同的SimpleDraweeView的显示.

    那么,如果要不影响,怎么办?很简单,让四个参数任一一个不同就行.

    Fresco中在listview之类的快速滑动时停止加载,滑动停止后恢复加载时调用的API是什么?

    话不多说,直接看代码.

    /**
         * 暂停网络请求
         * 在listview快速滑动时使用
         */
        public static void pause(){
            Fresco.getImagePipeline().pause();
        }
    
    
        /**
         * 恢复网络请求
         * 当滑动停止时使用
         */
        public static void resume(){
            Fresco.getImagePipeline().resume();
        }

    gif图片无法显示成圆形,怎么办?(当然有的情况下,jpg也无法显示圆形) –加一层和图片的parentview 背景色一样的圆形遮罩即可:

    public static void setCircle( SimpleDraweeView draweeView,int bgColor){
            RoundingParams roundingParams = RoundingParams.asCircle();//这个方法在某些情况下无法成圆,比如gif
            roundingParams.setOverlayColor(bgColor);//加一层遮罩,这个是关键方法
            draweeView.getHierarchy().setRoundingParams(roundingParams);
        }

    当然,无法圆角化,也是同样加一层遮罩:

    很多app都有清除磁盘缓存的功能,那么fresco怎么清除缓存呢?

    /**
         * 清除磁盘缓存
         */
        public static void clearDiskCache(){
            Fresco.getImagePipeline().clearDiskCaches();
        }
    
    
        /**
         * 清除单张图片的磁盘缓存
         * @param url
         */
        public static void clearCacheByUrl(String url){
            ImagePipeline imagePipeline = Fresco.getImagePipeline();
            Uri uri = Uri.parse(url);
           // imagePipeline.evictFromMemoryCache(uri);
            imagePipeline.evictFromDiskCache(uri);
            //imagePipeline.evictFromCache(uri);//这个包含了从内存移除和从硬盘移除
        }

    已经设置了downsampling和resize,但是加载很大的gif图还是很卡,怎么办

    gif是一帧一帧的图组成,编码的方式跟jpg和png等图片有很大区别,downsampling和resize对gif是无效的.gif图太大了?

    分辨率一大的话,那文件不得十几M几十M?下载都要等很久吧?

    还是在服务器端放小一点的图吧…

    高斯模糊

    高斯模糊是app里设置一些背景效果 常用到的手段.

    在fresco中,可以通过postprocessor来实现,也可以自己拿到bitmap后将bitmap模糊化后设置到ImageView或SimpleDraweeView(这个不建议,会消除掉SimpleDraweeView的层级结构,变成单纯的ImageView)上.

    推荐前一种: 用到别人封装好的BlurPostprocessor:

        /**
         * 高斯模糊后显示
         * @param url
         * @param draweeView
         * @param width draweeView的宽
         * @param height draweeView的高
         * @param context
         * @param radius  高斯模糊的半径, 每一个像素都取周边(多少个)像素的平均值
         * @param sampling 采样率 原本是设置到BlurPostprocessor上的,因为高斯模糊本身对图片清晰度要求就不高,
         *                 所以此处直接设置到ResizeOptions上,直接让解码生成的bitmap就缩小,而BlurPostprocessor
         *                 内部sampling设置为1,无需再缩
         */
        public static void loadUrlInBlur(String url,SimpleDraweeView draweeView,
                                         int width,int height,Context context,int radius,int sampling){
    
            if (sampling<2){
                sampling = 2;
            }
            loadUrl(url,draweeView,new BlurPostprocessor(context,radius,1),width/sampling,height/sampling,null);
    
        }

    当然,拿到bitmap自己去模糊也有开源框架:NativeStackBlur

     private Bitmap fastBlur(Bitmap bkg, int radius,int downSampling) {
            if (downSampling < 2){
                downSampling = 2;
            }
    
            Bitmap smallBitmap =   Bitmap.createScaledBitmap(bkg,bkg.getWidth()/downSampling,bkg.getHeight()/downSampling,true);
    
            return   NativeStackBlur.process(smallBitmap, radius);
        }

    也可以通过这个方法来封装自己的BlurPostprocessor,具体可参考上面封装好的BlurPostprocessor.

    工具类FrescoUtils地址:https://github.com/glassLake/FrescoUtlis

    展开全文
  • 目录 基本用法 Glide的基本用法: Picasso的基本用法: 库的大小和方法的数量 ...Glide 和 Picasso 是目前 Android 上最流行的图片加载库。...这两个库也都确实提供了大量图片加载的功能,而且也都经过了很多应...
  • 安卓网络框架比较

    2018-10-30 15:11:09
    引言 目前网络请求框架也比较多,本文针对封装的比较完善的Volley,Okhttp,Retrofit研究比较了,才知道选择哪个最适合。... 一.Volley 来源: Volley详解 ...google推出的异步网络请求框架和图片加载框架。特...
  • 图片加载框架Glide的使用解析及其高级用法 ...Glide在安卓中不算是一个新的技术,但却是使用的比较火热的图片加载框架。在GitHuB上有28.2K颗星也体现了广大开发者对Glide的喜爱. 2.普通图片加载方法与Glide...
  • Glide作为安卓开发常用的图片加载库,有许多实用而且强大的功能,那么,今天就来总结一番,这次把比较常见的都写出来,但并不是全部哦。 在介绍之前,先来说说什么是Glide吧: 在泰国举行的谷歌开发者论坛上,...
  • 手写高并发图片加载框架图片加载框架在当前已经是相当的成熟了,想要有创新。就是需要从图片加载速度和图片缓存, 还有内存占用和生命周期监控上去做文章。glide做的就比较好。出自squre团队的良心作品。 该团队可以...
  • 图片加载速度快,用户体验好(最大的优点);需要比较大的内存空间进行图片缓存 2)Glide如何导包? compile 'com.github.bumptech.glide:glide:3.5.2' compile 'com.github.bumptech.glide:glide:3.7.0' 3)Glide基本...
  • 安卓自定义View实现加载gif图片

    千次阅读 2017-11-26 09:28:16
    开题:加载GIF的场景在安卓开发中还比较常见,网上也有一些三方法的框架会支持对gif的加载,在上篇博客为大家推荐的图片加载库Glide也支持gif的加载Glide工具类的简单封装,今天给大家分享通过自定义View的方式加载...
  • 安卓框架

    2018-10-16 16:07:36
    Xutils 注解模块,网络模块,图片加载模块,数据库模块 Picasso 图形缓存库,可以实现图片下载和缓存功能 PullToRefresh 是一套实现非常好的下拉刷新库,支持ListVIew,GridView,ScrollView,webView,...
  • bigappleui ...(2)ZoomImageView,继承ImageView,在加载图片显示后,可对图片缩放,旋转查看。 (3)RoundedImageView,该也继承ImageView,用来显示圆角图片。 (4)SlipButton,模拟滑块按钮。
  • 密码可见不可见的空间:...直接就能用 动态图 gif 加载框架 implementation ‘pl.droidsonroids.gif:android-gif-drawable:1.2.17’ 圆角图片:implementation ‘de.hdodenhof:circleimageview:3...
  • 安卓开发框架系列开篇

    千次阅读 2017-10-09 10:56:30
    近期研究了几个主流开源框架的使用,有Retrofit(网络请求),RxJava(异步操作),GreenDAO(数据库操作),EventBus(事件通信),Glide、Fresco(图片加载),ButterKnife(资源绑定),Dagger(依赖注入)。...
  • 2.xUtils加载图片功能 3.xUtils操作数据库 4.xUtils的网络请求 一、xUtils简介: xUtils是基于Afinal开发的目前功能比较完善的一个Android开源框架,官网:https://github.com/wyouflf/xUtils3 xUtils 包含了orm...
  • 安卓常用,比较有用的第三方框架

    千次阅读 2017-08-07 10:54:44
    1、Picasso 优点 (1) 自带统计监控功能 ...支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的...(3) 支持延迟到图片尺寸计算完成加载   (4) 支持飞行模式、并发线程数根据网络类型而变 手机
  • 安卓andbase框架源码解读(二)

    万次阅读 2015-03-05 23:31:12
    上一次分析了andbase框架的AbActivity 安卓andbase框架源码解读(一),不知道有没有让大家对这个框架产生点兴趣,这次我要分析的是一个平常比较常用也比较简单但是还挺烦人的知识点:下载图片,当然现在有很多框架...
  • 鼎鼎大名的安卓图片加载框架Glide有一个可能大家比较少用的功能,就是RecyclerView滑动的预加载组件RecyclerViewPreloader,它的功能就是在滑动列表的时候提前加载指定item图片数据进入内存,使得滑动的时候可以立即...
  • 相对比较完善的手机端网页图片上传完成了,其中碰见了很多问题,由于是第一次弄,就一个个的解决掉,最后这个目前来说是比较满意的版本。 开发环境为 Bootstrap框架,另外需要引进一个JS用于判断图片拍摄的角度问题...
  • 考虑到几乎所有app都必备图片加载框架,所以需要自己实现图片加载接口。 图片预览控件来自:TouchImageView https://github.com/MikeOrtiz/TouchImageView // 只要在调用前初始化就可以了 PhotoSelector.init(new ...
  • 安卓orm框架,用得比较多的就GreenDao,Ormlite 安卓Json解析 Android 单元测试 Android 开源软件 Android 开发辅助工具 Android 推送(含IM) Android后端等服务 Android 应用内测平台 Android社会化分享,短信验证...
  • 内涵两个文件夹,一个myeclip服务器,一个安卓eclips,相信大家平时做Android应用的时候,开源图片加载框架应运而生,比较著名的就是Universal-Image-Loader,相信很多朋友都听过或者使用过这个强大的图片加载框架,...
  • BitmapUtils和大多数图片加载框架一样,都是基于内存-文件-网络三级缓存。也就是加载图片的时候首先从内存缓存中取,如果没有再从文件缓存中取,如果文件缓存没有取到,就从网络下载图片并且加入内存和文件缓存。 这...

空空如也

空空如也

1 2 3 4
收藏数 64
精华内容 25
关键字:

安卓图片加载框架比较