学习Picasso(毕加索)
来源:互联网 发布:知有多少个同音字 编辑:程序博客网 时间:2024/04/27 16:38
Picasso 完美兼容 OkHttp3.3,缓存优化两不误
Tamic 专注移动开发!更多文章请关注http://www.jianshu.com/p/6241950f9daf
为何在Fresco,Glide这么强大的背景下,我又想起了当初的Picasso,又为何写这篇文章?是因为最近项目采用了square公司的RxAndroid,Retrfit和OKhttp, 不得不联想到这个公司曾经还有款图片加载Picasso,所以采用了square公司的全家桶来进行项目开发,为了减少开发成本和也防止Apk增大,毕竟一个公司的框架之前兼容性不用担心,那么请让我们回顾一下Picass之路
首先先让我们看看主流图片加载库
Picasso,Square公司的开源项目 ,和Square的网络库一起能发挥最大作用。占用内存小,自身不带缓存,需依赖OKhttps实现缓存,不支持gif图片
Fresco,FB的明星项目,也是2015最火的项目之一,匿名共享缓存等机制保证低端机表现极佳,但是源代码基于C/C++,阅读困难度提升。效率高,sdk库占用包体积比较大
Glide,Google员工私人项目,但是Google很多项目在用,占用内存小,减低oom更靠谱,相对Picasso在Gif方面有优势,并自带缓存功能!
我做了一个实验对比 用一个普通listview加载50张图片,并快速滑动列表,下面分别是glide和picasso消耗内存图
分析后得出 一个占用内存大 一个占用cpu资源大, 这种区别是由于picasso只缓存一张大图,每次加载根据imagview的大小裁剪,因此消耗的cpu资源高,glide是分别存储不同尺寸的小图,每次不用计算,因此消耗内存比较多,加载速度相对Picasso也快,但也很耗流量.
为了避免OOM, 我毫不犹豫选择了消耗内存较小的picasso, Fresco不用说都是加载速度第一的框架,采用c库 ,我没做集成测试,具体消耗多少cpu资源我无法给出数据,据说业界第一,但是对apk大小要求的很可能不太合适,这里对Apk包体积要求不高的项目优先的首选。
喜欢glide的朋友可以看看这篇文章 :http://mrfu.me/2016/02/27/Glide_Getting_Started/
实验测试并做了简单比较后,为何还要继续说Picasso,不是说他有多块多流畅,只是当你使用了square公司其他的开源项目,会发现他们都会依赖okhttp,okhttp的强大不言而喻,今天只介绍piacsso相关的,说说picasso(官方:https://github.com/square/picasso) 的一些常用技巧!
Picasso
使用方式:
配置gradle
dependencies {ccompile 'com.squareup.picasso:picasso:2.5.2'compile 'com.squareup.okhttp3:okhttp:3.3.1'compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'}
据说目前的2.5.3已修复了2.52无法兼容okhttp3的问题,但我还是选择了2.52版本。
用法
Picasso.with(getApplication()).load(url).into(imageView);
以上用法很简单,加载图片时提供url插入到imageview即可,picasso其他强大功还没有太多的理解的同学请Follow Me!
裁剪图片
Picasso.with(getApplication()).resize(width, height);
这句方法会出现bug,误用!
请用Transformation来进行转义实现:
Picasso.with(getApplication()) .load(url) .transform(new PaTransformation(width, height)).into(imageView);
Transformation可以拦截到picasoo返回的bitmap,拿着bitmap随心所欲!
public class TamicTransformation implements Transformation {private int width;private int height;private String key;public PaTransformation(int width, int height) { this(width, height, width + "*" + height);}public PaTransformation(int width, int height, String key) { this.width = width; this.height = height; this.key = key;}@Overridepublic Bitmap transform(Bitmap source) { 略 拿着source进行裁剪缩放即可 if (result != source) { // Same bitmap is returned if sizes are the same source.recycle(); } return result;}@Overridepublic String key() { return key;}
}
列如处理圆形头像
public class CircleTransformation implements Transformation { private static final int STROKE_WIDTH = 5; @Override public Bitmap transform(Bitmap source) { int size = Math.min(source.getWidth(), source.getHeight()); int x = (source.getWidth() - size) / 2; int y = (source.getHeight() - size) / 2; Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); if (squaredBitmap != source) { source.recycle(); } Bitmap bitmap = Bitmap.createBitmap(size, size,source.getConfig()); Canvas canvas = new Canvas(bitmap); Paint avatarPaint = new Paint(); BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);avatarPaint.setShader(shader); Paint outlinePaint = new Paint(); outlinePaint.setColor(Color.WHITE); outlinePaint.setStyle(Paint.Style.STROKE); outlinePaint.setStrokeWidth(STROKE_WIDTH); outlinePaint.setAntiAlias(true); float r = size / 2f; canvas.drawCircle(r, r, r, avatarPaint); canvas.drawCircle(r, r, r - STROKE_WIDTH / 2, outlinePaint); squaredBitmap.recycle(); return bitmap; } @Override public String key() { return "circle)"; }}
接着设置渲染模式
Picasso.with(getApplication()) .fit().centerCrop()
清空缓存
新的版本2.52 已经无法直接拿到之前的cache,因此可以用Picasso.invalidate()的实现清楚缓存!
以前我们可以这样
Clear.clearCache(Picasso.with(context));
但现在 不行了
稍加封装成了这样子:
void clearCache(Uri uri, File file, String path) {if (!TextUtils.isEmpty(uri.toString())) {mPicasso.invalidate(uri);return;}if (!NullUtils.isNull(file)) {mPicasso.invalidate(file);return;}if (!TextUtils.isEmpty(path)) {mPicasso.invalidate(path);}}
当然也可以这样!
Picasso.with(getContext()).load(Url).memoryPolicy(MemoryPolicy.NO_CACHE).into(image);
在加载图片时直接不让做缓存!
加入缓存
当然2.5.2没做对oKhttp3.3的兼容,因此我们加入自定义的cilent,对okhttp做下缓存定制,请照着下面姿势作
构建OkHttpClient
// creat the OkHttpClient. OkHttpClient client =new OkHttpClient .Builder() .cache(new Cache("你的缓存路径", 1000*1024)) .addInterceptor(new CaheInterceptor(context, null)) .addNetworkInterceptor(new CaheInterceptor(context, null)) .build();
拦截器Interceptor
拦截器大家都不陌生,尤其是玩过okhttp和retofit的朋友,那肯定是拦截http的拦截请求和响应的,
public class CaheInterceptor implements Interceptor {private Context context;public CaheInterceptor(@NonNull Context context) { this.context = context;}@Overridepublic Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (NetworkUtil.isNetworkAvailable(context)) { Response response = chain.proceed(request); // read from cache for 60 s int maxAge = 300; String cacheControl = request.cacheControl().toString(); Log.e("Tamic", maxAge+ "s load cahe:" + cacheControl); return response.newBuilder() .removeHeader("Pragma") .removeHeader("Cache-Control") .header("Cache-Control", "public, max-age=" + maxAge) .build(); } else { Log.e("Tamic", " no network load cahe"); request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); Response response = chain.proceed(request); //set cahe times is 3 days int maxStale = 60 * 60 * 24 * 3; return response.newBuilder() .removeHeader("Pragma") .removeHeader("Cache-Control") .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) .build(); }}
}
添加到Picasso中
// Generate the global default Picasso instance. Picasso mPicasso = getPicasso(context, null); mPicasso.setLoggingEnabled(true);}
自定义DownLoader
为了兼容okhttp3.31 实现下载器!
public class ImageDownLoader implements Downloader {OkHttpClient client = null;public ImageDownLoader(OkHttpClient client) { this.client = client;}@Overridepublic Response load(Uri uri, int networkPolicy) throws IOException { CacheControl cacheControl = null; if (networkPolicy != 0) { if (NetworkPolicy.isOfflineOnly(networkPolicy)) { cacheControl = CacheControl.FORCE_CACHE; } else { CacheControl.Builder builder = new CacheControl.Builder(); if (!NetworkPolicy.shouldReadFromDiskCache(networkPolicy)) { builder.noCache(); } if (!NetworkPolicy.shouldWriteToDiskCache(networkPolicy)) { builder.noStore(); } cacheControl = builder.build(); } } Request.Builder builder = new Request.Builder().url(uri.toString()); if (cacheControl != null) { builder.cacheControl(cacheControl); } okhttp3.Response response = client.newCall(builder.build()).execute(); int responseCode = response.code(); if (responseCode >= 300) { response.body().close(); throw new ResponseException(responseCode + " " + response.message(), networkPolicy, responseCode); } boolean fromCache = response.cacheResponse() != null; ResponseBody responseBody = response.body(); return new Response(responseBody.byteStream(), fromCache, responseBody.contentLength());}@Overridepublic void shutdown() { Cache cache = client.cache(); if (cache != null) { try { cache.close(); } catch (IOException ignored) { } }}
}
接着将ImageDownLoader 加入到Picasso
/**
* Download Big Image only, Not singleton but shared cache */ public Picasso getPicasso(Context context) { OkHttpClient client = getProgressBarClient(); return new Picasso.Builder(context) .downloader(new ImageDownLoader(client)) .build();}
/**
* Not singleton */private OkHttpClient getProgressBarClient() { return client.newBuilder() .addInterceptor(new CaheInterceptor(context)) .addNetworkInterceptor(new CaheInterceptor(contextr)) .build();}
这样我们在做图片加载时 就可以:
getPicasso(context) .load(Url).into(image)
因此用了Picasso我们可以直接将缓存策略用到retrofit上去,其实一箭双雕,大大简化了开发成本!
优化相关
优化不缓存策略
public RequestCreator skipMemoryCache(RequestCreator requestCreator) { return requestCreator.memoryPolicy(MemoryPolicy.NO_STORE, MemoryPolicy.NO_CACHE) .networkPolicy(NetworkPolicy.NO_STORE, NetworkPolicy.NO_CACHE);}
降低内存消耗
设置RGB_565编码格式,降低内存消耗
public RequestCreator cutDownMemory(RequestCreator requestCreator) { return requestCreator.config(Bitmap.Config.RGB_565);}
取消加载
public class TamicImageView extends ImageView {public TamicImageView(Context context) { this(context, null, 0);}public TamicImageView(Context context, AttributeSet attrs) { this(context, attrs, 0);}public TamicImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);}@Overrideprotected void onDetachedFromWindow() { super.onDetachedFromWindow(); // 不可见时释放Bitmap setImageDrawable(null); // 暂停加载 mPicasso.pauseTag(this);}
}
还有很多api,比如
requestCreator.tag(tag);设置key
requestCreator.error(); 设置加载失败图片
mPicasso.pauseTag(); 暂停加载
mPicasso.resumeTag();恢复加载
mPicasso.cancelRequest();取消加载
requestCreator.priority()优先级
- requestCreator..rotate() 旋转之类
后记
总之虽然picasso 并不是最快的图片加载框架,但是他在基本的加载本地和网络图片基础上,还能很好的提供了让我们自我扩展能力,其扩展性和适应性更强,相信你结合了ohttp+ rxJava + Picasso 后你会发现他确实适合你!
- 学习Picasso(毕加索)
- Picasso(毕加索)框架 学习笔记
- Android Picasso(毕加索)
- Picasso网络图片加载 (毕加索)
- Picasso(毕加索)加载圆形图片、圆角图片
- Picasso学习
- Picasso学习笔记
- Picasso学习笔记
- Glide VS Picasso 学习
- Picasso源码学习
- picasso学习笔记
- 《Picasso源码学习》
- Picasso源码学习
- Picasso学习笔记
- 盗版毕加索
- Picasso 图片框架的学习
- Picasso使用学习(一)
- Picasso使用学习(二)
- popuwindows
- Python日期时间
- SimpleDateFormat实现字符串与日期之间的转换
- certmonger卡住先进入字符终端界面,之后正常进入图形界面
- iOS学习资源汇总(开源项目、第三方库、技术博客等等)
- 学习Picasso(毕加索)
- 性能测试基础知识41条精华问答
- js to progress bar
- df和du显示的磁盘空间使用情况不一致的原因及处理
- Android中Activity启动模式launchermode和intent.addFlags
- 错误:Could not instantiate bean class [java.util.List]: Specified class is an interface
- 小艾笔记--H.264视频编解码原理整理(三)
- Uber/优步App动画效果启动页实现
- CentOS 6.5 + Nginx 1.8.0 + PHP 5.6(with PHP-FPM) 负载均衡源码安装 之 (一)Nginx安装篇