picasso图片缓存框架
picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能。
picasso使用简单,如下
- Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
主要有以下一些特性:
- 在adapter中回收和取消当前的下载;
- 使用最少的内存完成复杂的图形转换操作;
- 自动的内存和硬盘缓存;
- 图形转换操作,如变换大小,旋转等,提供了接口来让用户可以自定义转换操作;
- 加载载网络或本地资源;
代码分析
Cache,缓存类
- this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
最后一个参数的解释:
- private void trimToSize(int maxSize) {
- while (true) {
- String key;
- Bitmap value;
- synchronized (this) {
- if (size < 0 || (map.isEmpty() && size != 0)) {
- throw new IllegalStateException(getClass().getName()
- + ".sizeOf() is reporting inconsistent results!");
- }
- if (size <= maxSize || map.isEmpty()) {
- break;
- }
- Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator()
- .next();
- key = toEvict.getKey();
- value = toEvict.getValue();
- map.remove(key);
- size -= Utils.getBitmapBytes(value);
- evictionCount++;
- }
- }
- }
Request,操作封装类
- public interface Transformation {
- /**
- * Transform the source bitmap into a new bitmap. If you create a new bitmap instance, you must
- * call {@link android.graphics.Bitmap#recycle()} on {@code source}. You may return the original
- * if no transformation is required.
- */
- Bitmap transform(Bitmap source);
- /**
- * Returns a unique key for the transformation, used for caching purposes. If the transformation
- * has parameters (e.g. size, scale factor, etc) then these should be part of the key.
- */
- String key();
- }
当操作封装好以后,会将Request传到另一个结构中Action。
Action
- @Override
- public void complete(Bitmap result, Picasso.LoadedFrom from) {
- if (result == null) {
- throw new AssertionError(String.format(
- "Attempted to complete action with no result!\n%s", this));
- }
- ImageView target = this.target.get();
- if (target == null) {
- return;
- }
- Context context = picasso.context;
- boolean debugging = picasso.debugging;
- PicassoDrawable.setBitmap(target, context, result, from, noFade,
- debugging);
- if (callback != null) {
- callback.onSuccess();
- }
- }
有了加载任务,具体的图片下载与解析是在哪里呢?这些都是耗时的操作,应该放在异步线程中进行,就是下面的BitmapHunter。
BitmapHunter
- @Override
- public void run() {
- try {
- Thread.currentThread()
- .setName(Utils.THREAD_PREFIX + data.getName());
- result = hunt();
- if (result == null) {
- dispatcher.dispatchFailed(this);
- } else {
- dispatcher.dispatchComplete(this);
- }
- } catch (IOException e) {
- exception = e;
- dispatcher.dispatchRetry(this);
- } catch (Exception e) {
- exception = e;
- dispatcher.dispatchFailed(this);
- } finally {
- Thread.currentThread().setName(Utils.THREAD_IDLE_NAME);
- }
- }
- abstract Bitmap decode(Request data) throws IOException;
- Bitmap hunt() throws IOException {
- Bitmap bitmap;
- if (!skipMemoryCache) {
- bitmap = cache.get(key);
- if (bitmap != null) {
- stats.dispatchCacheHit();
- loadedFrom = MEMORY;
- return bitmap;
- }
- }
- bitmap = decode(data);
- if (bitmap != null) {
- stats.dispatchBitmapDecoded(bitmap);
- if (data.needsTransformation() || exifRotation != 0) {
- synchronized (DECODE_LOCK) {
- if (data.needsMatrixTransform() || exifRotation != 0) {
- bitmap = transformResult(data, bitmap, exifRotation);
- }
- if (data.hasCustomTransformations()) {
- bitmap = applyCustomTransformations(
- data.transformations, bitmap);
- }
- }
- stats.dispatchBitmapTransformed(bitmap);
- }
- }
- return bitmap;
- }
可以看到,在decode生成原始bitmap,之后会做需要的转换transformResult和applyCustomTransformations。最后在将最终的结果传递到上层dispatcher.dispatchComplete(this)。
Dispatcher任务调度器
Dispatcher内有一个HandlerThread,所有的请求都会通过这个thread转换,也就是请求也是异步的,这样应该是为了Ui线程更加流畅,同时保证请求的顺序,因为handler的消息队列。
外部调用的是dispatchXXX方法,然后通过handler将请求转换到对应的performXXX方法。
例如生成Action以后就会调用dispather的dispatchSubmit()来请求执行,
- void dispatchSubmit(Action action) {
- handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
- }
handler接到消息后转换到performSubmit方法
- void performSubmit(Action action) {
- BitmapHunter hunter = hunterMap.get(action.getKey());
- if (hunter != null) {
- hunter.attach(action);
- return;
- }
- if (service.isShutdown()) {
- return;
- }
- hunter = forRequest(context, action.getPicasso(), this, cache, stats,
- action, downloader);
- hunter.future = service.submit(hunter);
- hunterMap.put(action.getKey(), hunter);
- }
这里将通过action得到具体的BitmapHunder,然后交给ExecutorService执行。
- public static Picasso with(Context context) {
- if (singleton == null) {
- singleton = new Builder(context).build();
- }
- return singleton;
- }
- public Picasso build() {
- Context context = this.context;
- if (downloader == null) {
- downloader = Utils.createDefaultDownloader(context);
- }
- if (cache == null) {
- cache = new LruCache(context);
- }
- if (service == null) {
- service = new PicassoExecutorService();
- }
- if (transformer == null) {
- transformer = RequestTransformer.IDENTITY;
- }
- Stats stats = new Stats(cache);
- Dispatcher dispatcher = new Dispatcher(context, service, HANDLER,
- downloader, cache, stats);
- return new Picasso(context, dispatcher, cache, listener,
- transformer, stats, debugging);
- }
在Picasso.with()的时候会将执行所需的所有必备元素创建出来,如缓存cache、执行executorService、调度dispatch等,在load()时创建Request,在into()中创建action、bitmapHunter,并最终交给dispatcher执行。
picasso图片缓存框架的更多相关文章
- Android图片缓存框架Glide
Android图片缓存框架Glide Glide是Google提供的一个组件.它具有获取.解码和展示视频剧照.图片.动画等功能.它提供了灵活的API,帮助开发者将Glide应用在几乎任何网络协议栈中. ...
- android图片缓存框架Android-Universal-Image-Loader
http://blog.csdn.net/king_is_everyone/article/details/34107081 最近跟同学们做了一个创业项目,其实跟以前做项目不同,以前大多数都是做web ...
- iOS图片缓存框架SDWebImage
本文转发至: http://blog.csdn.net/uxyheaven/article/details/7909373 http://www.cocoachina.com/ios/20141212 ...
- android图片缓存框架Android-Universal-Image-Loader(二)
http://blog.csdn.net/king_is_everyone/article/details/35595515 这篇打算直接告诉大家怎么用吧,其实这个也不是很难的框架,大致使用过程如下: ...
- 通过案例快速学会Picasso图片缓存库
picasso是Square公司开源的一个Android图形缓存库,官网地址http://square.github.io/picasso/,可以实现图片下载和缓存功能. 下载地址:ht ...
- Android图片缓存之初识Glide
前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架.技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自己的实 ...
- 安卓高级 Android图片缓存之初识Glide
前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架.技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自己的实 ...
- Android图片缓存之初识Glide(三)
前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架.技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自己的实 ...
- Android图片缓存之Bitmap详解
前言: 最近准备研究一下图片缓存框架,基于这个想法觉得还是先了解有关图片缓存的基础知识,今天重点学习一下Bitmap.BitmapFactory这两个类. 图片缓存相关博客地址: Android图片缓 ...
随机推荐
- poj 2425 AChessGame(博弈)
A Chess Game Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 3791 Accepted: 1549 Desc ...
- [bzoj4923]K小值查询
来自FallDream的博客,未经允许,请勿转载,谢谢. 维护一个长度为n的正整数序列a_1,a_2,...,a_n,支持以下两种操作: 1 k,将序列a从小到大排序,输出a_k的值. 2 k,将所有 ...
- [BZOJ]1095 Hide捉迷藏(ZJOI2007)
一道神题,两种神做法. Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特 ...
- [APIO2012]
来自FallDream的博客,未经允许,请勿转载,谢谢. --------------------------------------------------- A.dispatching 派遣 上次 ...
- [APIO2016]
2016的题貌似是韩国棒子出的,好丧啊.... 看了题解还想了好久...... ------------------------------------------------- A.Boat 有n个 ...
- 12_Python的(匿名函数)Lambda表达式_Python编程之路
Python作为一门高级语言,与很多编程语言一样都具有匿名函数这一特征 匿名函数,也就Lambda表达式,通俗来讲就是不用命名的方法,直接定义,直接用即可 创建匿名函数需要用到Lambda关键字,下面 ...
- 移动端手势双击(MouseDown也可以在移动端响应,但是帧率太低)
void Update() { if (Input.touchCount > 0)//手指数量 { if(Input.GetTouch(0).phase == TouchPhase.Began ...
- Redis学习汇总
[Redis教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使用redis 4.学会安装redis 5.学会启动redis 6.使用redis客户端 7.redis数据结构 – ...
- Day 1 Python简单程序
一.高级语言和低级语言 最初的计算机程序都是用0和1的序列表示的,程序员直接使用的是机器指令,无需翻译,从纸带打孔输入即可执行得到结果.后来为了方便记忆,就将用0.1序列表示的机器指令都用符号助记 ...
- Spring-cloud(六) Hystrix入门
前提 一个可用的Eureka注册中心(文中以之前博客中双节点注册中心,不重要) 一个连接到这个注册中心的服务提供者 快速入门 项目搭建 搭建一个新maven项目,artifactid为Ribbon-c ...