Picasso是什么?

它是一个图片的加载和缓存库,它能以最简单的方式来加载一张图片,目前最新的版本为2.5.2我们可以到如下的官网下载最新的jar包,或者在Android studio 在module build.gradle配置文件中加入如下的配置:
Picasso 官网

compile 'com.squareup.picasso:picasso:2.5.2'

Picasso的用法十分简单,并且不仅仅能加载网络资源,也能加载本地图片,Android资源文件,以及使用URI地址对图片进行加载。

创建Picasso实例:

  • 标准的Picasso实例
    创建Picasso实例的最简单方法就是调用它的with方法并传入对应的context.这时候创建的是标准的Picasso对象。
    如下所示:
    Picasso.with(context)
  • 自定义Picasso实例

但是有时候标准的Picasso对象并不能满足我们特定情形的要求,所以就需要使用 Picasso.Builder:

Picasso.Builder customPicassoBuilder = new Picasso.Builder(context);
Picasso customPicasso = picassoBuilder.build();
picasso
.load(imageUrl)
.into(imageView1);
  • 如何将自定义的Picasso作为全局使用的Picasso:
    这里需要注意的是如果在创建Picasso的时候Picasso已经被设置过这时出现异常,在定义完自定义的Picasso后在在Picasso.with(context)调用之后进行设置也会出现该异常,所以需要添加一个try{ }catch{ }
    try{
    Picasso.Builder picassoBuilder = new Picasso.Builder(context);
    Picasso picasso = picassoBuilder.build();
    Picasso.setSingletonInstance(picasso);
    }catch(IllegalStateException ignored){

    }

使用Picasso加载缓存图片:

  • 加载Android资源文件:
    ImageView imageView = (ImageView) findViewById(R.id.imageView);
    int resId = R.mipmap.ic_launcher;
    Picasso.with(context).load(resId).into(imageView);
  • 加载本地文件:
    ImageView imageView = (ImageView) findViewById(R.id.imageView);
    File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test.png");
    Picasso.with(context).load(file).into(imageView);
  • 加载网络资源:
    ImageView imageView = (ImageView) findViewById(R.id.imageView);
    String imageUrl = "http://xxxxxxxxxxxxxxxxxxxxxx";
    Picasso.with(context).load(imageUrl).into(imageView);
  • 在ListView中使用:
    public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView==null){
    convertView = View.inflate(context,R.layout.item_picasso,null);
    }
    ImageView imageView = (ImageView)convertView;
    if (TextUtils.isEmpty(imageUrls[position])){
    //如果是空uri图片那么取消请求
    Picasso.with(context).cancelRequest(imageView);
    imageView.setImageDrawable(null);
    }else {
    //加载图片
    Picasso.with(context)
    .load(imageUrls[position])
    .placeholder(R.mipmap.ic_launcher)//如果没有图片的时候的占位图
    .error(R.mipmap.ic_launcher) //发生错误时候的图片
    .into((ImageView) convertView);
    }
    return convertView;
    }

一些常见的属性设置:

  • 自定义图片大小处理:
    ImageView imageView = (ImageView) findViewById(R.id.imageView);
    int resId = R.mipmap.ic_launcher;
    Picasso.with(context).load(resId).resize(1028, 2000).into(imageView);
  • onlyScaleDown
    如果调用了resize(x,y)来设定图片的大小的话,Picasso一般会重新以改变图片的加载质量,但是如果我们的原图是比我们从新resize的新图规格大的时候,我们就可以调用onlyScaleDown()来直接进行展示而不再重新计算.
    Picasso
    .with(context)
    .load(xxxxxxxxxxx)
    .resize(6000, 2000)
    .onlyScaleDown()
    .into(xxxxxxxxx);
  • 图片的缩放拉伸处理
    Picasso提供了两种选择用户处理图片的拉伸处理:
    centerCrop() - 图片会被剪切
    centerInside()- 图片会被完整的展示,可能图片不会填充满ImageView。
Picasso
.with(context)
.load(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
.resize(600, 200)
.centerInside()
.into(xxxxxxxxxxxxxxxxx);

  • 图片的旋转处理

当我们对一张图片只需要进行简单的旋转处理时,只需要调用传入大于0小于360的旋转角度即可:

Picasso.with(context)
.load(xxxxxxxxxxxxxxx)
.rotate(180f)
.into(xxxxxxx);

除了上述的旋转,还可以为旋转设定一个支点,只需要将上述的rotate换作rotate(float degrees, float pivotX, float pivotY) 即可:

Picasso
.with(context)
.load(xxxxxxxxxxxxxxxx)
.rotate(145f, 20f, 10f)
.into(xxxxxxxxx);
  • 对无效Uri的响应图片:

    .placeholder(R.mipmap.ic_launcher)  
  • 对访问错误时的响应图片

    .error(R.mipmap.error)  
  • 不使用默认的淡入的效果,加载的图片直接显示在ImageView上:

    Picasso
    .with(context)
    .load(imageUri)
    .noFade() //不使用默认的淡入的效果
    .into(imageView);
  • 第二次图片进来的时候不使用占位图片noPlaceholder

    Picasso
    .with(context)
    .load(imageUri)
    .placeholder(R.mipmap.ic_launcher)
    .into(imageView, new Callback() {
    @Override
    public void onSuccess() {
    Picasso
    .with(context)
    .load(imageUri)
    .noPlaceholder()
    .into(imageView);
    }

    @Override
    public void onError() {

    }
    });
  • 使用fit 优化减小内存空间占用
    使用fit Picasso会对图片的大小及ImageView控件进行测量,计算出最佳的大小及最佳的图片质量以减少内存;

    Picasso
    .with(context)
    .load(yyyyyyyyyyyyyy)
    .fit()
    .into(rrrrrrrrrrrrrr);
  • 设置图片加载的优先级

Picasso支持设置优先级,分为HIGH, MEDIUM, 和 LOW,所有的加载默认优先级为MEDIUM,但是这种设置并不能保证图片一定会优先加载,只是会偏向于优先加载,这个和给某个变量声明为regiter是一个道理的

Picasso
.with(context)
.load(xxxxxxxxxxxx)
.fit()
.priority(Picasso.Priority.HIGH)
.into(xxxxxxxxxxxx);
  • 使用TAG来处理请求:

在ListView中使用网络图片是很常见的,在我们滑动ListView的时候Picasso是会不断在进行网络请求,取消请求,再次请求,取消请求的状态进行的,这往往会对性能产生严重影响。使用TAG标签,可以在用户在快速滑动的时候全部停止请求,只有在滑动停止时再去请求。
Picasso提供了三种设置Tag的方式

暂停标记 pauseTag()
恢复标记 resumeTag()
取消标记 cancleTag()

用法:
首先为某个Picasso对象添加一个标签:

Picasso
.with(context)
.load(xxxxxxxxxxxxxxxxxxx)
.tag("ListView Item")
.into(xxxxxxxxxxxxxxxxxx;

然后实现滑动监听,在监听中操作Tag

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
final Picasso picasso = Picasso.with(context);
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) {
picasso.resumeTag("ListView Item");
} else {
picasso.pauseTag("ListView Item");
}
}

cancleTag() 一般在不再需要进行网络请求的时候进行调用,并且在使用TAG的时候要记住如果tag状态为pause或者resume的话,Picasso会对tag持有一个引用,如果没有及时处理当前Activity退出的时候,执行垃圾回收的时候,就会出现内存泄露,所以要注意在onDestory()方法中进行相应处理。以避免这种情况的发生。

  • 使用 fetch() .get() .target()

.fetch() 不会返回Bitmap,更不会展现在ImageView上,它只是将数据加载到本地和内存中从而加快后期的加载速度。
.get() 使用get会返回一个Bitmap,但是该方法不能在主线程中调用,因为会造成线程阻塞;
.target() 上面的例子我们都是使用.into()方法,将图片资源加载到ImageView中,除了这种方法还可以使用方法来实现同样的功能:

private Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
//加载成功后会得到一个bitmap,可以自定义操作
}

@Override
public void onBitmapFailed(Drawable errorDrawable) {
// 加载失败的时候会执行这里的方法
}

@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {

}
};
Picasso
.with(context)
.load(xxxxx)
.into(target);
  • 在自定义Notifications上使用Picasso:

使用Picasso可以将图片加载到RemoteViews上,从而可以在锁屏,Widget,以及Notification上使用Picasso。下面是对应的用法:

RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.item_picasso);
Picasso.with(MainActivity.this)
.load(xxxxxxxxx)
.into(remoteViews,R.id.remoteview_layout,NOTIFICATION_ID,notification);
  • 对图片进行模糊处理

首先通过实现Transformation 接口来实现一个Transformation

public class BlurByPicasso implements Transformation {
RenderScript rs;
public BlurByPicasso(Context context) {
super();
rs = RenderScript.create(context);
}
@Override
public Bitmap transform(Bitmap bitmap) {
Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
Allocation output = Allocation.createTyped(rs, input.getType());
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
script.setRadius(15);
script.forEach(output);
output.copyTo(blurredBitmap);
bitmap.recycle();
return blurredBitmap;
}

@Override
public String key() {
return "blurbyPicasso";
}
}

为其设置效果:

Picasso
.with(context)
.load(xxxxxxxxxxxx)
.transform(new BlurByPicasso(context))
.into(imageView);
  • 对图片进行多种处理

除了对图片进行单种处理外还可以将多个处理应用到Picasso上,这就需要用到transform(List<? extends Transformation> transformations)

````
public class TransformationOne implements Transformation {
private final Picasso picasso;
public TransformationOne(Picasso picasso) {
this.picasso = picasso;
}
@Override
public Bitmap transform(Bitmap source) {
//在这里对图片进行各种转换
return result;
}
@Override
public String key() {
return “TransformationOne”;
}
}

public class TransformationTwo implements Transformation {
private final Picasso picasso;
public TransformationTwo(Picasso picasso) {
this.picasso = picasso;
}
@Override
public Bitmap transform(Bitmap source) {
//在这里对图片进行各种转换
return result;
}
@Override
public String key() {
return “TransformationTwo”;
}
}

接下创建一个Transformation 列表,将上述的转换添加到列表上:
List<Transformation> transformations = new ArrayList<>();
transformations.add(new TransformationOne(Picasso.with(context)));
transformations.add(new TransformationTwo(Picasso.with(context)));
将Transformation集合应用到Picasso上:

Picasso
.with(context)
.load(xxxxxxxxxxxxxxxxxx)
.transform(transformations)
.into(imageView);


### Picasso的缓存配置:

* Picasso默认的缓存分配大小规则如下:
LRU缓存占应用程序可用内存的15%
本地缓存占到硬盘空间的2%但不超过50M并且不小于5M
Picasso默认开启3个线程来进行本地与网络之间的访问
Picasso加载图片顺序, 内存–>本地–>网络
* 存储策略

可能有的时候你不想让Picasso去内存中进行读取这种情况下可以通过memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional),MemoryPolicy有如下两种选择:

NO_CACHE - 不将图片缓存在内存中
NO_STORE - 这个适用于所加载的图片只加载一次就没用了,这种情况Picasso使用完图片就不会在内存及本地缓存了
Picasso
.with(context)
.load(xxxxxxxxxx)
.memoryPolicy(MemoryPolicy.NO_CACHE)
.into(imageView);
或者:
Picasso
.with(context)
.load(xxxxxxxxxx)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.into(imageView);


调用memoryPolicy(MemoryPolicy.NO_CACHE)虽然能避免Picasso从内存中读取资源,但是并不能避免从本地读取资源,Picasso提供了另一个策略NetworkPolicy:
就像MemoryPolicy负责管理内存缓存一样,NetworkPolicy就是负责管理本地缓存的,并且二者的用法一模一样:

NO_CACHE - 让Picasso跳过从本地读取资源这一过程
NO_STORE - 让Picasso不进行本地图片缓存
OFFLINE - 让Picasso加载图片的时候只从本地读取,除非联网正常并且本地找不到资源的情况下

```
Picasso
.with(context)
.load(xxxxxxxxxx)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(imageView);

同时memoryPolicy和networkPolicy还可以一起使用:

Picasso  
.with(context)
.load(xxxxxxxxxx)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(imageView);

图片缓存指示器

  • 使用图片缓存指示器:
    要想知道到底图片来源于何处可以使用setIndicatorsEnabled(true)打开图片来源指示器:
    Picasso  
    .with(context)
    .load(xxxxxxxxxx)
    .setIndicatorsEnabled(true);
    使用图片来源指示器后就会在图片的左上角出现一个颜色标记蓝色,绿色,红色;
    蓝色 - 从内存中获取,是最佳性能展示
    绿色 - 从本地获取,性能一般
    红色 - 从网络加载,性能最差

对应Log信息输出:

  • 使用图片加载Log查看图片加载信息:
    如果要查看图片加载所用的时间可以使用setLoggingEnabled(true),这时候每张网络请求的资源所用的时间可以以Log的形式输出:
    Picasso  
    .with(context)
    .setLoggingEnabled(true);
    如果要对整个图片的加载尺寸等数据进行查看可以使用getSnapshot方法
StatsSnapshot picassosnapStats = Picasso.with(context).getSnapshot();  
Log.d("xiaohai.lin", picassosnapStats.toString());
Contents
  1. 1. Picasso是什么?
  • 创建Picasso实例:
  • 使用Picasso加载缓存图片:
  • 一些常见的属性设置:
  • 图片缓存指示器
  • 对应Log信息输出: