学习Picasso(毕加索)

2023-12-07 13:48
文章标签 学习 毕加索 picasso

本文主要是介绍学习Picasso(毕加索),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Picasso 完美兼容 OkHttp3.3,缓存优化两不误

字数1327  阅读792  评论0 

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消耗内存图


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 {
c
compile '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;
}@Override
public Bitmap transform(Bitmap source) {略 拿着source进行裁剪缩放即可if (result != source) {// Same bitmap is returned if sizes are the samesource.recycle();}return result;
}@Override
public 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;
}@Override
public Response intercept(Chain chain) throws IOException {Request request = chain.request();if (NetworkUtil.isNetworkAvailable(context)) {Response response = chain.proceed(request);// read from cache for 60 sint 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 daysint 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;
}@Override
public 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());}@Override
public 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);}@Override
protected void onDetachedFromWindow() {super.onDetachedFromWindow();// 不可见时释放BitmapsetImageDrawable(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(毕加索)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/466110

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件