Picasso 是Square 公司开源的Android 端的图片加载和缓存框架。Square 真是一家良心公司啊,为我们Android开发者贡献了很多优秀的开源项目有木有!像什么Rerefoit 、OkHttp、LeakCanary、Picasso等等都是非常火的开源项目。回到正题,除了使用简单方便,Picasso还能自动帮我们做以下事情:

  • 处理Adapter 中ImageView的回收和取消下载。
  • 使用最小的内存 来做复杂的图片变换。比如高斯模糊,圆角、圆形等处理。
  • 自动帮我们缓存图片。内存和磁盘缓存。

以上只是列出了Picasso 比较核心的几点,其实它的优点远远不止这些,接下来就看一下如何使用Picasso。

                  Picasso-Android.png

本文目录

0,添加依赖
1, 加载显示图片
2,Placeholder & noPlaceholder & noFade
3 , 设置图片尺寸(Resize)、缩放(Scale)和裁剪(Crop)
4,图片旋转Rotation()
5 , 转换器Transformation
6,请求优先级
7,Tag管理请求
8,同步/异步加载图片
9,缓存(Disk 和 Memory)
10,Debug 和日志
11,Picasso 扩展

正文

0. 添加依赖

要使用Picasso,首先我们要添加版本依赖,去官网或者Github 看一下当前的最新版本(截止本文最新版本为2.5.2),然后在build.gradle中添加依赖:

1. 加载显示图片

将Picasso添加到项目之后,我们就可以用它来加载图片了,使用方法非常简单:

只需要一行代码就完成了加载图片到显示的整个过程,链式调用,非常简洁,其实有三步,一次调用了三个方法:

  • with(Context) 获取一个Picasso单例,参数是一个Context上下文
  • load(String) 调用load 方法加载图片
  • into (ImageView) 将图片显示在对应的View上,可以是ImageView,也可以是实现了Target j接口的自定义View。

上面演示了加载一张网络图片,它还支持其它形式的图片加载,加载文件图片,加载本地资源图片,加载一个Uri 路径给的图片,提供了几个重载的方法:

load(Uri uri) 加载一个以Uri路径给的图片

load(File file) 加载File中的图片

load(int resourceId) 加载本地资源图片

提醒:上面介绍了load的几个重载方法,加载不同资源的图片,另外提醒注意一下load(String path)接受String 参数的这个方法,参数String 可以是一个网络图片url,也可以是file 路径、content资源 和Android Resource。看一下源码的注释。

要使用string 参数加载上面的几种资源,除了网络url,其它几种需要加上对应前缀,file文件路径前缀:file: , content 添加前缀:content: ,Android Resource 添加:android.resource:

2. placeholder& error & noPlaceholder & noFade

通过上面的第一步我们就可以通过Picasso 加载图片了,我们的项目中通常最常用的就是加载网络图片,但是由于网络环境的差异,有时侯加载网络图片的过程有点慢,这样界面上就会显示空ImageView什么也看不见,用户体验非常不好。其实以前用过ImageLoader的同学都知道,ImageLoader 是可以设置加载中显示默认图片的,Picasso当然也给我们提供了这个功能。

placeholder
placeholder提供一张在网络请求还没有完成时显示的图片,它必须是本地图片,代码如下:

设置placeholder之后,在加载图片的时候,就可以显示设置的默认图了,提升用户体验。
error
和placeholder 的用法一样,error 提供一张在加载图片出错的情况下显示的默认图

noPlaceholder
这个方法的意思就是:在调用into的时候明确告诉你没有占位图设置。根据这个方法签名的解释是阻止View被回收的时候Picasso清空target或者设置一个应用的占位图。需要注意的是placeholder和noPlaceholder 不能同时应用在同一个请求上,会抛异常。

noFade
无论你是否设置了占位图,Picasso 从磁盘或者网络加载图片时,into 显示到ImageView 都会有一个简单的渐入过度效果,让你的UI视觉效果更柔顺丝滑一点,如果你不要这个渐入的效果,就调用noFade方法。

3. 设置图片尺寸(Resize)、缩放(Scale)和裁剪(Crop)

Resize(int w,int h)
在项目中,为了带宽、内存使用和下载速度等考虑,服务端给我们的图片的size 应该和我们View 实际的size一样的,但是实际情况并非如此,服务端可能给我们一些奇怪的尺寸的图片,我们可以使用resize(int w,int hei) 来重新设置尺寸。

resize()方法接受的参数的单位是pixels,还有一个可以设置dp单位的方法,将你的尺寸写在dimens.xml文件中,然后用resizeDimen(int targetWidthResId, int targetHeightResId)方法

onlyScaleDown
当调用了resize 方法重新设置图片尺寸的时候,调用onlyScaleDown 方法,只有当原始图片的尺寸大于我们指定的尺寸时,resize才起作用,如:

只有当原来的图片尺寸大于4000 x 2000的时候,resize 才起作用。
图片裁剪 centerCrop()
这个属性应该不陌生吧!ImageView 的ScaleType 就有这个属性。当我们使用resize 来重新设置图片的尺寸的时候,你会发现有些图片拉伸或者扭曲了(使用ImageView的时候碰到过吧),我要避免这种情况,Picasso 同样给我们提供了一个方法,centerCrop,充满ImageView 的边界,居中裁剪。

centerInside
上面的centerCrop是可能看不到全部图片的,如果你想让View将图片展示完全,可以用centerInside,但是如果图片尺寸小于View尺寸的话,是不能充满View边界的。

fit
fit 是干什的呢?上面我们需要用resize()来指定我们需要的图片的尺寸,那就是说在程序中需要我们计算我们需要的尺寸(固定大小的除外),这样很麻烦,fit 方法就帮我们解决了这个问题。fit 它会自动测量我们的View的大小,然后内部调用reszie方法把图片裁剪到View的大小,这就帮我们做了计算size和调用resize 这2步。非常方便。代码如下:

使用fit 还是会出现拉伸扭曲的情况,因此最好配合前面的centerCrop使用,代码如下:

看一下对比图:
fit(会拉伸):

          image_fit.png

fit & centerCrop (不会拉伸):

          fit_centerCrop.png

注意:特别注意,
1,fit 只对ImageView 有效
2,使用fit时,ImageView 宽和高不能为wrap_content,很好理解,因为它要测量宽高。

4. 图片旋转Rotation()

在图片显示到ImageView 之前,还可以对图片做一些旋转操作,调用rotate(int degree)方法

这个方法它是以(0,0)点旋转,但是有些时候我们并不想以(0,0)点旋转,还提供了另外一个方法可以指定原点:

  • rotate(float degrees, float pivotX, float pivotY) 以(pivotX, pivotY)为原点旋转

5. 转换器Transformation

Transformation 这就是Picasso的一个非常强大的功能了,它允许你在load图片 -> into ImageView 中间这个过成对图片做一系列的变换。比如你要做图片高斯模糊、添加圆角、做度灰处理、圆形图片等等都可以通过Transformation来完成。

来看一个高斯模糊的例子:

第一步, 首先定义一个转换器继承Transformation

  public static class BlurTransformation implements Transformation{

        RenderScript rs;

        public BlurTransformation(Context context) {
super();
rs = RenderScript.create(context);
} @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(); // 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";
}
}

第二步, 加载图片的时候,在into 方法前面调用 transform方法 应用Transformation

  Picasso.with(this).load(URL)
.placeholder(R.drawable.default_bg)
.error(R.drawable.error_iamge)
.transform(new BlurTransformation(this))
.into(mBlurImage);

看一下效果图:

        transformation.png

上面为原图,下面为高斯模糊图

是不是很强大,任何复杂的变换都可以通过Transformation 来做。

还不止于此,还有更强大的功能。可以在一个请求上应用多个Transformation

比如:我想先做个度灰处理然后在做一个高斯模糊图:

第一步, 定义一个度灰的Transformation

  public static class GrayTransformation implements Transformation{

        @Override
public Bitmap transform(Bitmap source) {
int width, height;
height = source.getHeight();
width = source.getWidth(); Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation();
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(source, , , paint); if(source!=null && source!=bmpGrayscale){
source.recycle();
}
return bmpGrayscale;
} @Override
public String key() {
return "gray";
}
}

第二步, 如果是多个Transformation操作,有两种方式应用
方式一:直接调用多次transform 方法,不会覆盖的。它只是保存到了一个List 里面

  Picasso.with(this).load(URL)
.placeholder(R.drawable.default_bg)
.error(R.drawable.error_iamge)
.fit()
.centerCrop()
.transform(new GrayTransformation())//度灰处理
.transform(new BlurTransformation(this))//高斯模糊
.into(mBlurImage);

需要注意调用的顺序
方式二:接受一个List,将Transformation 放大list 里

     List<Transformation> transformations = new ArrayList<>();
transformations.add(new GrayTransformation());
transformations.add(new BlurTransformation(this)); Picasso.with(this).load(URL)
.placeholder(R.drawable.default_bg)
.error(R.drawable.error_iamge)
.fit()
.centerCrop()
.transform(transformations)
.into(mBlurImage);

效果图:

          gray_blur.png

如上图,第一张为度灰操作,第二张为 度灰+高斯模糊

另外发现了一个开源库,专门写了很多好玩的Transformation,有兴趣的可以看一下:
picasso-transformations

6. 请求优先级

Picasso 为请求设置有优先级,有三种优先级,LOW、NORMAL、HIGH。默认情况下都是NORMAL,除了调用fetch 方法,fetch 方法的优先级是LOW。

可以通过priority方法设置请求的优先级,这会影响请求的执行顺序,但是这是不能保证的,它只会往高的优先级靠拢。代码如下:

7. Tag管理请求

Picasso 允许我们为一个请求设置tag来管理请求,看一下对应的几个方法:
下面3个方法是Picasso这个类的:

  • cancelTag(Object tag) 取消设置了给定tag的所有请求
  • pauseTag(Object tag) 暂停设置了给定tag 的所有请求
  • resumeTag(Object tag) resume 被暂停的给定tag的所有请求

还有一个方法是RequestCreator的:

  • tag(Object tag) 为请求设置tag

几个方法的意思也很明确,就是我们可以暂停、resume、和取消请求,可以用在哪些场景呢?

场景一: 比如一个照片流列表,当我们快速滑动列表浏览照片的时候,后台会一直发起请求加载照片的,这可能会导致卡顿,那么我们就可以为每个请求设置一个相同的Tag,在快速滑动的时候,调用pauseTag暂停请求,当滑动停止的时候,调用resumeTag恢复请求,这样的体验是不是就会更好一些呢。

Adapter中添加如下代码:

Activity中为RecyclerView添加滑动监听:

场景二: 比如一个照片流列表界面,在弱网环境下,加载很慢,退出这个界面时可能会有很多请求没有完成,这个时候我们就可 以通过tag 来取消请求了。

8. 同步/异步加载图片

Picasso 加载图片也有同步/异步两种方式
同步get() 
很简单,同步加载使用get() 方法,返回一个Bitmap 对象,代码如下:

注意:使用同步方式加载,不能放在主线程来做。

异步fetch()
一般直接加载图片通过into显示到ImageView 是异步的方式,除此之外,还提供了2个异步的方法:

  • fetch() 异步方式加载图片
  • fetch(Callback callback) 异步方式加载图片并给一个回调接口。

这里就要吐槽一下接口设计了,回调并没有返回Bitmap, 不知道作者是怎么考虑的,只是一个通知效果,知道请求失败还是成功。
**fetch 方法异步加载图片并没有返回Bitmap,这个方法在请求成功之后,将结果存到了缓存,包括磁盘和内存缓存。所以使用这种方式加载图片适用于这种场景:知道稍后会加载图片,使用fetch 先加载缓存,起到一个预加载的效果。 **

9. 缓存(Disk 和 Memory)

Picasso 有内存缓存(Memory)和磁盘缓存( Disk), 首先来看一下源码中对于缓存的介绍:

  • LRU memory cache of 15% the available application RAM
  • Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only
    available on API 14+ <em>or</em> if you are using a standalone library that provides a disk cache on all API levels like OkHttp)
  • Three download threads for disk and network access.

可以看出,内存缓存是使用的LRU 策略的缓存实现,它的大小是内存大小的15%,可以自定义它的大小,最后在扩展那一章节再讲,磁盘缓存是磁盘容量的2%但是不超过50M,不少于5M。处理一个请求的时候,按照这个顺讯检查:memory->disk->network 。先检查有木有内存缓存,如果命中,直接返回结果,否则检查磁盘缓存,命中则返回结果,没有命中则从网上获取。

默认情况下,Picasso 内存缓存和磁盘缓存都开启了的,也就是加载图片的时候,内存和磁盘都缓存了,但是有些时候,我们并不需要缓存,比如说:加载一张大图片的时候,如果再内存中保存一份,很容易造成OOM,这时候我们只希望有磁盘缓存,而不希望缓存到内存,因此就需要我们设置缓存策略了。Picasso 提供了这样的方法。

方式一:memoryPolicy 设置内存缓存策略
就像上面所说的,有时候我们不希望有内存缓存,我们可以通过 memoryPolicy 来设置。MemoryPolicy是一个枚举,有两个值

NO_CACHE:表示处理请求的时候跳过检查内存缓存
**NO_STORE: ** 表示请求成功之后,不将最终的结果存到内存。

示例代码如下:

方式二:networkPolicy 设置磁盘缓存策略

和内存缓存一样,加载一张图片的时候,你也可以跳过磁盘缓存,和内存缓存策略的控制方式一样,磁盘缓存调用方法networkPolicy(NetworkPolicy policy, NetworkPolicy... additional) , NetworkPolicy是一个枚举类型,有三个值:

NO_CACHE: 表示处理请求的时候跳过处理磁盘缓存
NO_STORE:表示请求成功后,不将结果缓存到Disk,但是这个只对OkHttp有效。
OFFLINE: 这个就跟 上面两个不一样了,如果networkPolicy方法用的是这个参数,那么Picasso会强制这次请求从缓存中获取结果,不会发起网络请求,不管缓存中能否获取到结果。

使用示例:

强制从缓存获取:

10. Debug 和日志

缓存指示器

上一节说了,Picasso 有内存缓存和磁盘缓存,先从内存获取,没有再去磁盘缓存获取,都有就从网络加载,网络加载是比较昂贵和耗时的。因此,作为一个开发者,我们往往需要加载的图片是从哪儿来的(内存、Disk还是网络),Picasso让我们很容易就实现了。只需要调用一个方法setIndicatorsEnabled(boolean)就可以了,它会在图片的左上角出现一个带色块的三角形标示,有3种颜色,绿色表示从内存加载、蓝色表示从磁盘加载、红色表示从网络加载。

效果图:

 
            cache_indicator.png

如上图所示,第一张图从网络获取,第二张从磁盘获取,第三张图从内存获取。

看一下源码中定义指示器的颜色:

可以很清楚看出,对应三种颜色代表着图片的来源。

日志
上面的指示器能够很好的帮助我们看出图片的来源,但是有时候我们需要更详细的信息,Picasso,可以打印一些日志,比如一些关键方法的执行时间等等,我们只需要调用setLoggingEnabled(true)方法,然后App在加载图片的过程中,我们就可以从logcat 看到一些关键的日志信息。

11. Picasso 扩展

到目前为止,Picasso的基本使用已经讲得差不多了,但是在实际项目中我们这可能还满足不了我们的需求,我们需要对它做一些自己的扩展,比如我们需要换缓存的位置、我们需要扩大缓存、自定义线程池、自定义下载器等等。这些都是可以的,接下来我们来看一下可以做哪些方面的扩展。

用Builder 自己构造一个Picasso Instance
我们来回顾一下前面是怎么用Picasso 加载图片的:

总共3步:
(1) 用with方法获取一个Picasso 示例
(2) 用load方法加载图片
(3) 用into 放法显示图片

首先Picasso是一个单例模式,我们每一次获取的示例都是默认提供给我们的实例。但是也可以不用它给的Instance,我们直接用builder来构造一个Picasso:

这样我们就构造了一个局部的Picasso实例,当然了,我们直接用new 了一个builder,然后build()生成了一个Picasso。这跟默认的通过with方法获取的实例是一样的。那么现在我们就可以配置一些自定义的功能了。

配置自定义下载器 downLoader
如果我们不想用默认提供的Downloader,那么我们可以自定义一个下载器然后配置进去。举个例子:

总共5步:
(1) 先自定义一个Downloader(只是举个例子,并没有实现):

(2) 然后通过builder 配置:

这样配置后,我们用build()生成的Picasso 实例来加载图片就会使用自定义的下载器来下载图片了。

(3) 配置缓存
前面说过,内存缓存是用的LRU Cahce ,大小是手机内存的15% ,如果你想缓存大小更大一点或者更小一点,可以自定义,然后配置。

上面只是一个简单的举例,当然了你可以自定义,也可以使用LRUCache,改变大小,改变存储路径等等。

提示: 很遗憾,好像没有提供改变磁盘缓存的接口,那就只能用默认的了。

(4) 配置线程池
Picasso 默认的线程池的核心线程数为3,如果你觉得不够用的话,可以配置自己需要的线程池,举个列子:

(5) 配置全局的 Picasso Instance
上面说的这些自定义配置项目都是应用在一个局部的Picasso instance 上的,我们不可能每一次使用都要重新配置一下,这样就太麻烦了。我们希望我们的这些自定义配置能在整个项目都应用上,并且只配置一次。其实Picasso 给我们提供了这样的方法。可以调用setSingletonInstance(Picasso picasso)就可以了,看一下这个方法的源码:

设置一个通过with方法返回的全局instance。我们只希望配置一次,所以,我们应该在Application 的onCreate方法中做全局配置就可以了。app一启动就配置好,然后直接和前面的使用方法一样,调用with方法获取Picasso instance 加载图片就OK了。

因此在Application 中添加如下代码:

然后应用这些自定义配置加载图片

用法和以前的一样,但是我们已经将我们的自定义配置应用上了。

结尾

以上就是对Picasso 用法的全部总结,如有什么问题,欢迎留言指正。Picasso真的是一个强大的图片加载缓存库,API 简单好用,而且是链式调用的(这点我特别喜欢)。官方文档写的比较简单,很多用法都要看源码和注释才知道。希望本文能给才开始使用Picasso 的同学一点帮助。

作者:依然范特稀西
链接:https://www.jianshu.com/p/c68a3b9ca07a
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Android Picasso最详细的使用指南的更多相关文章

  1. 【转】Syncthing – 数据同步利器---自己的网盘,详细安装配置指南,内网使用,发现服务器配置

    Syncthing – 数据同步利器---自己的网盘,详细安装配置指南,内网使用,发现服务器配置 原贴:https://www.cnblogs.com/jackadam/p/8568833.html ...

  2. 开源Android容器化框架Atlas开发者指南

    Atlas是古希腊神话中的天神,是波士顿动力公司的机器人,借助搜索引擎,得以发现这个名词背后许许多多的含义.在手机淘宝,Atlas是一个扎根于Android客户端的一个组件化容器框架,相比神话中用手和 ...

  3. OpenCV On Android环境配置最新&最全指南(Android Studio篇)

    本文是从本人简书上搬运而来,属本人原创,如有转载,请注明出处:http://www.jianshu.com/p/6e16c0429044 简介 本文是<OpenCV On Android环境配置 ...

  4. Android SQLite 数据库详细介绍

    Android SQLite 数据库详细介绍 我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用 ...

  5. 【转载】一行代码加载网络图片到ImageView——Android Picasso

    原文链接:一句代码加载网络图片到ImageView——Android Picasso  注意:此处使用下面代码需要先配置一下gradle,下载所需包. 具体操作如下图: compile 'com.sq ...

  6. Android BLE蓝牙详细解读

    代码地址如下:http://www.demodashi.com/demo/15062.html 随着物联网时代的到来,越来越多的智能硬件设备开始流行起来,比如智能手环.心率检测仪.以及各式各样的智能家 ...

  7. android的logcat详细用法!

    from://http://www.miui.com/article-272-1.html [技术交流]android的logcat详细用法! logcat是Android中一个命令行工具,可以用于得 ...

  8. Android平台签名证书(.keystore)生成指南

    来源:https://ask.dcloud.net.cn/article/35777 Android平台签名证书(.keystore)生成指南 分类:HTML5+ Android证书 Android平 ...

  9. OpenCV On Android环境配置最新&最全指南(Eclipse篇)

    简介 本教程是经过本人多次踩坑,并参考网上众多OpenCV On Android的配置教程总结而来,尽希望能帮助学习移动图像处理的朋友们少走弯路.这也是本人第一次在简书上发布文章,如有不足,希望各位d ...

随机推荐

  1. JavaWeb开发SSM框架搭建详解

    1.需要用到的jar包:由于很多的jar包不好下载,我直接上传到百度网盘: 很多,而且不好下载,我已经整理好好了: 链接:https://pan.baidu.com/s/1iIFprmstp86uKz ...

  2. [Swift]LeetCode787. K 站中转内最便宜的航班 | Cheapest Flights Within K Stops

    There are n cities connected by m flights. Each fight starts from city u and arrives at v with a pri ...

  3. [Swift]LeetCode1005. K 次取反后最大化的数组和 | Maximize Sum Of Array After K Negations

    Given an array A of integers, we must modify the array in the following way: we choose an i and repl ...

  4. Unable to preventDefault inside passive event listener due to target being treated as passive

    Unable to preventDefault inside passive event listener due to target being treated as passive 今天在做项目 ...

  5. BBS论坛(一)

    1.1.项目结构搭建 (1)创建flask项目Perfect_bbs,然后搭建项目结构如下: (2)构建蓝图 cms/views.py # cmd/views.py from flask import ...

  6. PHP常用函数总结(180多个)[持续更新中...]

    PHP常用函数总结 本文源文件(markdown): https://github.com/yanglr/AlgoSolutions/blob/master/PHP常用函数总结(160多个).md 数 ...

  7. 手把手用Monkey写一个压测脚本

    版权声明: 本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有. 允许有条件转载,转载请附带底部二维码. 一.为什么需要一个测试脚本? 昨天讲解了Android Monkey命 ...

  8. linux下(fdisk,gdisk,parted)三种分区工具比较

    1 2种分区结构简介 MBR分区 硬盘主引导记录MBR由4个部分组成 主引导程序(偏移地址0000H--0088H),它负责从活动分区中装载,并运行系统引导程序. 出错信息数据区,偏移地址0089H- ...

  9. Linux vi常用命令

    vi常用命令[Ctrl] + [f] 屏幕『向前』移动一页(常用)[Ctrl] + [b] 屏幕『向后』移动一页(常用)0 这是数字『 0 』:移动到这一行的最前面字符处(常用)$ 移动到这一行的最后 ...

  10. 流式大数据计算实践(6)----Storm简介&使用&安装

    一.前言 1.这一文开始进入Storm流式计算框架的学习 二.Storm简介 1.Storm与Hadoop的区别就是,Hadoop是一个离线执行的作业,执行完毕就结束了,而Storm是可以源源不断的接 ...