Android 图片加载框架 Picasso
一:介绍
Picasso 是 Square 公司开源的 Android 端的图片加载和缓存框架
1. 增加依赖:目前 github 上的版本 2.7
在 app 下的 build.gradle 下增加依赖
implementation 'com.squareup.picasso:picasso:2.5.2'
二:应用
1. 根本应用
Picasso.with(this).load(url).placeholder(R.mipmap.ic_launcher).into(imageView);
//with 下传递的是 Context
//load 下有 4 个重载办法,传递别离是 url 加载一个以 Uri 门路的图片,File 加载 File 中图片,String,resourceId 加载本地资源的图片
//placeholder 是加载一个占位图
//into 加载到控件中,也能够是实现了 Target j 接口的自定义 View。
into 办法的一些源码
public void into(Target target) {long started = System.nanoTime();
// 查看线程
// 先查看主否在主线程运行,如果不是在主线程就会抛出一个应该在主线程运行的异样
checkMain();
if (target == null) {throw new IllegalArgumentException("Target must not be null.");
}
if (deferred) {throw new IllegalStateException("Fit cannot be used with a Target.");
}
// 判断是否加载 url
//data.hasImage():这里的 data 是在之前初始化的 Request.Builder 对象,它外面蕴含 url 地址,resourceId 和默认配置,这里是判断 uri 或 resourceId 是否为空为 0,如果是的话就勾销 imageview 的申请:picasso.cancelRequest(target);
if (!data.hasImage()) {picasso.cancelRequest(target);
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
return;
}
2. 占位符 placeholder,error,noPlaceholder,noFade
们的我的项目中通常最罕用的就是加载网络图片,然而因为网络环境的差别,有时侯加载网络图片的过程有点慢,这样界面上就会显示空 ImageView 什么也看不见,用户体验十分不好
placeholder
提供一张在网络申请还没申请实现时显示的图片,必须是本地图片
Picasso.with(this).load(url).placeholder(R.mipmap.ic_launcher).into(imageView);
error
error 提供一张在加载图片出错的状况下显示的默认图
Picasso.with(this).load(url).error(R.mipmap.ic_launcher).into(imageView);
noPlaceholder
在调用 into 的时候明确通知你没有占位图设置。依据这个办法签名的解释是阻止 View 被回收的时候 Picasso 清空 target 或者设置一个利用的占位图。须要留神的是 placeholder 和 noPlaceholder 不能同时利用在同一个申请上,会抛异样。
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher).into(imageView);
noFade
无论你是否设置了占位图,Picasso 从磁盘或者网络加载图片时,into 显示到 ImageView 都会有一个简略的渐入适度成果,让你的 UI 视觉效果更柔顺丝滑一点,如果你不要这个渐入的成果,就调用 noFade 办法。
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher).noFade().into(imageView);
3. 设置图片的尺寸(resize), 缩放(scale), 裁剪(crop)
resize(int w,int h)
为了带宽、内存应用和下载速度等思考,服务端给咱们的图片的 size 应该和咱们 View 理论的 size 一样的,然而理论状况并非如此,服务端可能给咱们一些奇怪的尺寸的图片,咱们能够应用 resize(int w,int hei) 来从新设置尺寸。
Picasso.with(this).load(url).resize(200,200).noPlaceholder().error(R.mipmap.ic_launcher).noFade().into(imageView);
resize()办法承受的参数的单位是 pixels, 还有一个能够设置 dp 单位的办法,将你的尺寸写在 dimens.xml 文件中,而后用 resizeDimen(int targetWidthResId, int targetHeightResId)办法
图片裁剪 centerCrop()
Picasso 同样给咱们提供了一个办法,centerCrop,充斥 ImageView 的边界,居中裁剪。
Picasso.with(this).load(url).resize(400,200).noPlaceholder().error(R.mipmap.ic_launcher).noFade().centerCrop().into(imageView);
centerInside
下面的 centerCrop 是可能看不到全副图片的,如果你想让 View 将图片展现齐全,能够用 centerInside,然而如果图片尺寸小于 View 尺寸的话,是不能充斥 View 边界的。
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher).noFade().resize(400,200).centerInside().into(imageView);
fit
fit 是干什的呢?下面咱们须要用 resize()来指定咱们须要的图片的尺寸,那就是说在程序中须要咱们计算咱们须要的尺寸(固定大小的除外),这样很麻烦,fit 办法就帮咱们解决了这个问题。fit 它会主动测量咱们的 View 的大小,而后外部调用 reszie 办法把图片裁剪到 View 的大小,这就帮咱们做了计算 size 和调用 resize 这 2 步
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher).noFade().resize(400,200).fit().centerInside().into(imageView);
图片旋转 rotate()
在图片显示到 ImageView 之前,还能够对图片做一些旋转操作,调用 rotate(int degree)办法
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher).noFade().rotate(180).into(imageView);
rotate(float degrees, float pivotX, float pivotY) 以 (pivotX, pivotY) 为原点旋转
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher).noFade().rotate(180,0,0).into(imageView);
4. 转换器 Transformation
Transformation 这就是 Picasso 的一个十分弱小的性能了,它容许你在 load 图片 -> into ImageView 两头这个过成对图片做一系列的变换。比方你要做图片高斯含糊、增加圆角、做度灰解决、圆形图片等等都能够通过 Transformation 来实现。
应用
Picasso.with(this).load(url).noPlaceholder().error(R.mipmap.ic_launcher)
.transform(new BlurTransformation(this))// 这里增加了一个转换器实现高斯含糊
.into(imageView);
那么咱们如何实现这个转换器了 BlurTransformation
public class BlurTransformation implements Transformation {
RenderScript rs;
public BlurTransformation(Context context) {super();
rs = RenderScript.create(context);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public Bitmap transform(Bitmap bitmap) {
// Create another bitmap that will hold the results of the filter.
Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
// Allocate memory for Renderscript to work with
Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
Allocation output = Allocation.createTyped(rs, input.getType());
// Load up an instance of the specific script that we want to use.
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
// Set the blur radius
script.setRadius(25);
// Start the ScriptIntrinisicBlur
script.forEach(output);
// Copy the output to the blurred bitmap
output.copyTo(blurredBitmap);
bitmap.recycle();
return blurredBitmap;
}
@Override
public String key() {return "blur";}
}
5. 同步 / 异步加载图片 get(),fetch()
同步 get()
很简略,同步加载应用 get() 办法,返回一个 Bitmap 对象
Bitmap bitmap=Picasso.with(this).load(url).get();
// 留神:应用同步办法不能放在主线程来做
异步 fetch()
个别间接加载图片通过 into 显示到 ImageView 是异步的形式,除此之外,还提供了 2 个异步的办法:
fetch() 异步形式加载图片
fetch(Callback callback) 异步形式加载图片并给一个回调接口
Picasso.with(this).load(url).fetch(new Callback() {
@Override
public void onSuccess() {}
@Override
public void onError() {}
});
fetch 办法异步加载图片并没有返回 Bitmap,这个办法在申请胜利之后,将后果存到了缓存,包含磁盘和内存缓存。所以应用这种形式加载图片实用于这种场景:晓得稍后会加载图片,应用 fetch 先加载缓存,起到一个预加载的成果。
6. 缓存(Disk 和 Memory)
Picasso 有内存缓存 (Memory) 和磁盘缓存(Disk)
默认状况下,Picasso 内存缓存和磁盘缓存都开启了的,也就是加载图片的时候,内存和磁盘都缓存了,然而有些时候,咱们并不需要缓存,比如说:加载一张大图片的时候,如果再内存中保留一份,很容易造成 OOM, 这时候咱们只心愿有磁盘缓存,而不心愿缓存到内存,因而就须要咱们设置缓存策略了。Picasso 提供了这样的办法
形式一:memoryPolicy 设置内存缓存策略
NO_CACHE:示意解决申请的时候跳过查看内存缓存
NO_STORE: 示意申请胜利之后,不将最终的后果存到内存。
Picasso.with(this).load(url).placeholder(R.mipmap.ic_launcher)
.memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)// 禁止内存缓存
.into(imageView);
之前咱们也有应用 skipMemoryCache 来禁止内存缓存,然而如同当初新的没有用了
Picasso.with(this).load(url).placeholder(R.mipmap.ic_launcher).skipMemoryCache().into(imageView);
那咱们就须要去看一下源码:
// 看源码标注废除
// 其实他也是调用 memoryPolicy,传递默认的 NO_CACHE,NO_STORE
/**
* @deprecated Use {@link #memoryPolicy(MemoryPolicy, MemoryPolicy...)} instead.
*/
@Deprecated public RequestCreator skipMemoryCache() {return memoryPolicy(NO_CACHE, NO_STORE);
}
/**
* Specifies the {@link MemoryPolicy} to use for this request. You may specify additional policy
* options using the varargs parameter.
*/
public RequestCreator memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional) {
// 不能为空,空异样
if (policy == null) {throw new IllegalArgumentException("Memory policy cannot be null.");
}
this.memoryPolicy |= policy.index;
// 不能为空,异样,故 2 个参数不能为空
if (additional == null) {throw new IllegalArgumentException("Memory policy cannot be null.");
}
if (additional.length > 0) {for (MemoryPolicy memoryPolicy : additional) {if (memoryPolicy == null) {throw new IllegalArgumentException("Memory policy cannot be null.");
}
this.memoryPolicy |= memoryPolicy.index;
}
}
return this;
}
// 依据源码查看 memoryPolicy 办法的参数不能为空
那么咱们看一下硬盘缓存
形式二:networkPolicy 设置磁盘缓存策略
NO_CACHE: 示意解决申请的时候跳过解决磁盘缓存
NO_STORE: 示意申请胜利后,不将后果缓存到 Disk,然而这个只对 OkHttp 无效。
OFFLINE: 这个就跟 下面两个不一样了,如果 networkPolicy 办法用的是这个参数,那么 Picasso 会强制这次申请从缓存中获取后果,不会发动网络申请,不论缓存中是否获取到后果。
Picasso.with(this).load(url).placeholder(R.mipmap.ic_launcher).networkPolicy(NetworkPolicy.NO_CACHE).into(imageView);
7.Debug 和日志
Picasso 有内存缓存和磁盘缓存,先从内存获取,没有再去磁盘缓存获取,都没有就从网络加载,网络加载是比拟低廉和耗时的。因而,作为一个开发者,咱们往往须要加载的图片是从哪儿来的(内存、Disk 还是网络),Picasso 让咱们很容易就实现了。只须要调用一个办法 setIndicatorsEnabled(boolean) 就能够了, 它会在图片的左上角呈现一个带色块的三角形标示,有 3 种颜色,绿色示意从内存加载、蓝色示意从磁盘加载、红色示意从网络加载。
日志
Picasso, 能够打印一些日志,比方一些要害办法的执行工夫等等,咱们只须要调用 setLoggingEnabled(true) 办法,而后 App 在加载图片的过程中,咱们就能够从 logcat 看到一些要害的日志信息。
三:Picasso 总结
1.Picasso 是下载图片而后缓存残缺的大小到本地,比如说图片的大小是 1080p 的,之后如果我须要同一张图片,就会返回这张 full size 的,如果我须要 resize,也是对这种 full size 的做 resize。
2.Picasso 则是用的 ARGB _8888 的设定。Glide 默认是用的 RGB_565 的设定
3. 加载工夫问题(当从网络加载 Picasso 快一些,当从内存加载 Glide 快一些)
当尝试加载一个图片的时候,两个库都会采纳先从缓存中读取,如果缓存中没有,再去下载的做法。
理论试验中,Picasso 会比 Glide 快一点。猜想可能的起因还是因为之前讲到的缓存机制导致,因为 Picasso 是间接把图加载到内存中,而 Glide 则须要扭转图片大小再加载到内存中去。这个应该是会消耗肯定的工夫。
然而,当加载图片从内存中的时候,Glide 则比 Picasso 要快。其原理还是因为缓存机制的区别。因为 Picasso 从缓存中拿到的图片,还要先去 resize 后,而后设定给 imageView,然而 Glide 则不须要这样。
4.Picasso.with(这里只能传入上下文) .
Glide.with, 前面能够传入上下文,activity 实例,FragmentActivity 实例,Fragement. 传入的对象要比前者多.
结尾:如果我看得更远一点的话,是因为我站在伟人的肩膀上