图片加载之Picasso使用

时间:2022-12-13 19:39:16

简介

PicassoSquare公司开源的一个Android图形缓存库,可以实现图片下载和缓存功能。

主要有以下一些特性:

  1. Adapter中回收和取消已经不在视野范围图片资源的加载,防止可能出现的图片错位;
  2. 使用复杂的图片压缩转换来尽可能的减少内存消耗;
  3. 使用最少的内存完成复杂的图形转换操作;
  4. 自带内存和硬盘缓存;
  5. 可加载网络或本地资源。

GitHub地址:

https://github.com/square/picasso

背景

Android系统作为图片资源加载的主角,它是通过图像的像素点来将图像加载到内存中的。现在一张500W的摄像头拍出的照片(2592x1936)加载到内存中需要大约19M的内存,如果你加入了在信号强度不一的网络中进行复杂的网络请求,并进行图片的缓存与其他处理时,你将会耗费大量的时间与精力来处理这些问题,但如果使用Picasso进行加载实现这些问题都将会得到很好的解决。

配置

build.gradle配置:

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

混淆配置:

-dontwarn com.squareup.okhttp.**

网络配置:

<uses-permission android:name="android.permission.INTERNET" />

图片加载

Picasso使用简单易用的接口,并有一个实现类Picasso,一个完整的图片加载请求至少需要三个参数:
with(Context context):上下文;
load(String path):加载图片的地址;
into(ImageView target):图片展示的ImageView

简单用例:

Picasso.with(mActivity)
.load(Constant.picUrl)
.into(mIvNetworkPictures);

其他加载方式:

可以加载资源文件、本地File文件、Uri地址等。

常用方法

1. .noFade()

Picasso的默认图片加载方式有一个淡入的效果,如果调用了noFade()方法后加载的图片将直接显示在ImageView上。

2. .noPlaceholder()

有一个场景,当你从网上加载了一张图片到Imageview上后,过了一段时间想在同一个ImageView上展示另外一张图片。这个时候你就会去调用Picasso进行二次请求,这时Picasso就会把之前的图片进行清除,可能展示的是.placeholder()状态的图片,给用户并不是很好的体验,如果调用了noPlaceholder()方法就不会出现这种情况了。

3. .resize(int targetWidth, int targetHeight)

如果图片很大或者想自定义图片的显示样式时,可以使用此方法来裁剪图片尺寸。

4. .onlyScaleDown()

如果调用了resize(width,height)方法的话,Picasso一般会重新计算以改变图片的加载质量,比如一张小图变成一张大图进行展示的时候。但是如果我们的原图是比重新resize的新图规格大的时候,我们就可以调用onlyScaleDown()来直接进行展示而不再重新计算,缩短图片的加载计算时间。

5. .centerInside()

图片会被完整的展示,可能图片不会填充满ImageView,也有可能会被拉伸或者挤压,一般是等比例缩小。

6. .centerCrop()

图片会被裁剪,但是图片质量没有什么区别,等比例放大。

7. .fit()

Picasso会对图片的大小及ImageView进行测量,计算出最佳的大小及最佳的图片质量来进行图片展示,减少内存的消耗并对视图没有影响。

8. .priority()

如果一个视图中顶部图片较大而底部图片较小,因为Picasso是异步加载,所以小图会先加载出来。但是对于用户来说或许更希望看到的是上面的图片先被加载而底部的图片后被加载,此时可使用此方法来设置图片加载的优先级。
注意:设置优先级并不能保证图片就一定会被优先加载,只是会偏向倾斜于先加载。

9. .tag()

为请求添加标记提升用户体验。比如在列表ListViewItem中加载了图片,当用户在快速滑动的时候可以设置停止请求,在滑动停止时再去加载请求,退出当前页面时取消请求。

Picasso提供了三种设置Tag的方式:

  1. 暂停标记:pauseTag()
  2. 可见标记:resumeTag()
  3. 取消标记:cancelTag()

在图片请求加载时添加标记:

Picasso.with(mActivity)
.load(Constant.picUrl)
.tag("mark")
.into(mIvNetworkPictures);

ListView实现滑动监听OnScrollListener

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

在页面进行跳转或者退出时取消请求:

@Override
protected void onDestroy() {
super.onDestroy();
Picasso.with(mActivity)
.cancelTag("mark");
}

注意:如果Tag状态为pause或者resume的时候,Picasso会对Tag持有一个引用,如果此时用户退出了当前Activity,垃圾回收机制进行回收的时候就可能会出现内存泄露,所以需要在onDestroy()方法中进行相应处理。

10. .fetch()

该方法会在后台异步加载一张图片,但是不会展示在ImageView上,也不会返回Bitmap,这个方法只是为了将获取到的资源加载到本地和内存当中,为后期的加载缩短时间。

11. .get()

该方法是一个异步线程,加载完成后会返回一个Bitmap,但是需要注意的是该方法不能在主线程中调用,因为会造成线程阻塞。

12. Target

之前调用into()方法是将获取到的资源加载到ImageView中,但我们还可以将资源作为回调放到Target中。

private Target target = new Target() {

@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

}

@Override
public void onBitmapFailed(Drawable errorDrawable) {

}

@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {

}
};

//然后进行调用即可

Picasso.with(mActivity)
.load(Constant.picUrl)
.into(target);

注意:可以使用.get()或者Target获取图片的Bitmap,但是当你使用Target时不能使用匿名内部类的方式,因为垃圾回收机制在你获取不到Bitmap的时候会把对象回收。

13. .rotate(float degrees)

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

14. .rotate(float degrees, float pivotX, float pivotY)

默认的图片旋转都是相对(0,0)进行旋转的,所以如果我们想自定义相对于某个点的旋转时可以调用以上方法。

15. .error

加载失败时的图片显示,如果重试3次(下载源代码可以根据需要修改)还是无法成功加载图片,则用错误占位符图片显示。

16. .placeholder()

加载过程中的图片显示。

17. 如果图片地址不存在或为空的时候怎么处理?

当图片地址不存在或为空时,可以先调用cancelRequest()方法取消网络请求,然后调用imageView.setImageDrawable(null)方法进行设置。

if (StringUtil.isEmpty(Constant.picUrl)) {
Picasso.with(mActivity)
.cancelRequest(mIvNetworkPictures);
mIvNetworkPictures.setImageDrawable(null);
}

18. Picasso在自定义Notification中的使用:

Picasso有一个功能是可以加载图片到RemoteViews上,而RemoteViews是用在Widget及自定义Notification布局中的,以下是其使用方式。

Picasso.with(mActivity)
.load(Constant.picUrl)
.into(remoteViews, R.id.iv_remoteView, notificationId, notification);

19. 模糊图片:

我们可以在图片进行展示之前对其进行配置后在展示,这时我们需要定义一个类实现Transformation接口,然后重写里面的方法。

 private class BlurTransformation implements Transformation {

RenderScript rs;

public BlurTransformation(Context context) {
rs = RenderScript.create(context);
}

@Override
public Bitmap transform(Bitmap bitmap) {
// 创建一个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(10);

//开始操作
script.forEach(output);

// 将结果copy到blurredBitmap中
output.copyTo(blurredBitmap);

//释放资源
bitmap.recycle();

return blurredBitmap;
}

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

//然后进行调用即可

Picasso.with(mActivity)
.load(Constant.picUrl)
.transform(new BlurTransformation(mActivity))
.into(mIvNetworkPictures);

20. 模糊+圆形:

Picasso给我们提供了一个这样的API,允许我们将参数设置为一个Transformations的集合transform(List<? extends Transformation> transformations),这就意味着我们可以对加载的资源进行一系列的操作。

private class CircleTransformation implements Transformation {

@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 paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);

float r = size / 2f;
canvas.drawCircle(r, r, r, paint);

squaredBitmap.recycle();
return bitmap;
}

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

//然后进行调用即可

List<Transformation> transformations = new ArrayList<>();
transformations.add(new CircleTransformation());
transformations.add(new BlurTransformation(mActivity));

Picasso.with(mActivity)
.load(Constant.picUrl)
.transform(transformations)
.into(mIvNetworkPictures);

21. 缓存机制:

Picasso默认的缓存分配大小特点:

  1. LRU缓存占应用程序可用内存的15%
  2. 本地缓存占硬盘空间的2%,但不超过50M且不小于5M(前提是这种情况只在4.0以上有效果或者你能像OKHttp那样提供一个本地缓存库来支持全平台);
  3. Picasso默认开启3个线程来进行本地与网络之间的访问;
  4. Picasso加载图片顺序为内存–>本地–>网络。

22. 内存策略:

MemoryPolicy负责管理内存缓存,可能有的时候你不想让Picasso去内存中进行读取而跳过此步骤,此时你可以在进行网络请求的时候调用memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional)方法。MemoryPolicy是一个枚举类型,只有两个值:NO_CACHENO_STORE

  1. NO_CACHE:让Picasso跳过从内存中读取图片这一操作;
  2. NO_STORE:如果你的图片只加载一次就不在使用了就可以设置该值,这样的话Picasso就不会在内存及本地进行缓存了。

代码示例:

Picasso.with(mActivity)
.load(Constant.picUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE)
.into(mIvNetworkPictures);

当然你也可以这样调用:

Picasso.with(mActivity)
.load(Constant.picUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.into(mIvNetworkPictures);

注意:调用memoryPolicy(MemoryPolicy.NO_CACHE)虽然能避免Picasso从内存中读取资源,但是并不能避免从本地读取资源。

23. 网络策略:

NetworkPolicy负责管理本地缓存,它也是一个枚举类型。

  1. NO_CACHE:跳过从本地读取资源这一过程;
  2. NO_STORE:不进行本地图片缓存;
  3. OFFLINE:加载图片的时候只从本地读取,除非网络正常且本地找不到资源的情况下。

示例代码:

Picasso.with(mActivity)
.load(Constant.picUrl)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(mIvNetworkPictures);

24. 缓存指示器,查看图片来源于何处:

当我们想知道所加载的图片来源于何处,是内存、本地还是从网络加载的时候,只需要在请求的时候调用.setIndicatorsEnabled(true)方法就好了。

Picasso.with(mActivity)
.setIndicatorsEnabled(true);

这样每张图片在显示的时候,左上角都会有一个小标记,分别是蓝色、绿色、红色三种颜色。

  1. 蓝色:从内存中获取,性能最佳;
  2. 绿色:从本地获取,性能一般;
  3. 红色:从网络加载,性能最差。

25. 查看图片加载用时:

在图片加载请求开始前调用.setLoggingEnabled(true)方法,通过输出日志的方式查看每张图片从网络请求加载时用的时间。

Picasso.with(mActivity)
.setLoggingEnabled(true);

Picasso.with(mActivity)
.load(Constant.picUrl)
.into(mIvNetworkPictures);

然后在控制台上查看日志信息如下:

D/Picasso: Main created [R0] Request{http://img.taopic.com/uploads/allimg/131009/235013-13100ZP54561.jpg}
D/Picasso: Dispatcher enqueued [R0]+8ms
D/Picasso: Hunter executing [R0]+9ms
D/Picasso: Hunter decoded [R0]+46ms
D/Picasso: Dispatcher batched [R0]+47ms for completion
D/Picasso: Dispatcher delivered [R0]+248ms
D/Picasso: Main completed [R0]+249ms from DISK

26. 图片加载分析:

查看图片的加载在内存中占用了多大可以调用StatsSnapshot即可。

StatsSnapshot statsSnapshot = Picasso.with(mActivity).getSnapshot();
LogUtil.e(Constant.LOG_TAG, "statsSnapshot:" + statsSnapshot.toString());

最后输出结果为:

statsSnapshot:StatsSnapshot{maxSize=19173961, size=0, cacheHits=0, cacheMisses=1, downloadCount=0, totalDownloadSize=0, averageDownloadSize=0, totalOriginalBitmapSize=0, totalTransformedBitmapSize=0, averageOriginalBitmapSize=0, averageTransformedBitmapSize=0, originalBitmapCount=0, transformedBitmapCount=0, timeStamp=1494484266351}

27. 创建一个Picasso

Picasso有一个直接的方法去创建一个它的实例,就是Picasso.Builder类,这样就可以创建属于我们自己的Picasso,而不是使用一个标准的Picasso

Picasso picasso = new Picasso.Builder(mActivity).build();

28. 标准创建方式:

我们最常用的就是直接调用Picasso.with(context)返回一个Picasso实例,这就是一个标准的Picasso

Picasso picasso = Picasso.with(mActivity);

29. 自定义创建Picasso实例:

调用Picasso.Builder创建的实例就是我们自定义的Picasso,当然它也默认实现了标准Picasso的所有功能,我们也可以像用标准的Picasso一样进行使用。

Picasso.Builder pb = new Picasso.Builder(mActivity);
Picasso picasso = pb.build();
picasso.load(Constant.picUrl)
.into(mIvNetworkPictures);

30. 将自定义Picasso变成全局使用:

在应用启动的时候调用Picasso.setSingletonInstance(picasso)方法,这样的话后面所有调用Picasso.with(context)返回的都是我们自定义的Picasso

Picasso.Builder pb = new Picasso.Builder(mActivity);
Picasso picasso = pb.build();
Picasso.setSingletonInstance(picasso);

31. 支持飞行模式,并发线程数可根据网络状态改变:

手机切换到飞行模式或网络状态改变时会自动调整线程池的最大并发数,默认线程数为3个线程,wifi状态下为4个线程,4G状态下为3个线程,3G状态下为2个线程,2G状态下为1个线程。

32. “无”本地缓存:

“无”本地缓存不是说没有本地缓存,而是Picasso自己没有实现,交给了Square的另外一个网络库OKHttp去实现。这样的好处是可以通过请求Response Header中的Cache-ControlExpired控制图片的过期时间。

自定义Picasso缓存

Picasso默认的缓存路径位于data/data/your package name/cache/picasso-cache/下。开发过程中我们难免会遇到一些需求,需要我们去修改图片的缓存路径。

分析:

我们注意到Picasso底层其实是使用OkHttp去下载图片,同时在设置Picasso的时候有一个.downloader(Downloader downloader)方法,我们可以传递进去一个OkHttpDownloader(...)

实现:

1.方法一

OkHttp依赖

compile 'com.squareup.okhttp:okhttp:2.4.0'

自定义缓存目录

FileUtil.getCachePath(mContext)

自定义创建Picasso实例并应用到全局

Picasso.Builder pb = new Picasso.Builder(this);
Picasso picasso = pb
.downloader(new OkHttpDownloader(new File(FileUtil.getCachePath(this))))
.build();
Picasso.setSingletonInstance(picasso);

2.方法二

当你把OkHttp升级到OkHttp3的时候,你会发现给downloader设置OkHttpDownloader()的时候,发现它并不支持OkHttp3。为了解决不能使用OkHttp3作为下载器的问题,Picasso作者jakewharton大神专门写了一个OkHttp3Downloader库。使用也非常简单,在项目build.gradle中添加依赖:

compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'

然后设置downloader的时候改为OkHttp3Downloader即可。

自定义缓存目录和缓存大小

// 设置缓存目录
File directory = new File(FileUtil.getCachePath(this));
if (!directory.exists()) {
directory.mkdirs();
}
// 设置缓存大小为运行时缓存的八分之一
long maxSize = Runtime.getRuntime().maxMemory() / 8;

自定义创建Picasso实例并应用到全局

OkHttpClient client = new OkHttpClient.Builder()
.cache(new Cache(directory, maxSize))
.build();

Picasso picasso = new Picasso.Builder(this)
.downloader(new OkHttp3Downloader(client))
.build();
Picasso.setSingletonInstance(picasso);

GlidePicasso比较

使用方法

1、Glide更容易使用,因为Glidewith()方法不光接受Context,还能接受ActivityFragmentContext会自动从它们获取。Picasso只接受Context
2、将Activity/Fragment作为with()参数的好处是图片加载将会和Activity/Fragment的生命周期保持一致。比如在onPause状态暂停加载,在onResume状态的时候又自动重新加载。

默认Bitmap格式

1、Glide默认Bitmap格式是RGB_565Picasso默认的Bitmap格式的是ARGB_8888
2、想要提高Glide的图片效果,Glide可以创建一个新的GlideModuleBitmap格式转换为ARGB_8888

public class GlideConfiguration implements GlideModule {

@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}

@Override
public void registerComponents(Context context, Glide glide) {

}
}

同时在AndroidManifest.xml中将GlideModule定义为meta-data

<meta-data
android:name="com.wiggins.glide.GlideConfiguration"
android:value="GlideModule" />

加载策略

1、Picasso是加载了全尺寸的图片到内存,然后让GPU来实时重绘大小。而Glide加载的大小和ImageView的大小是一致的,因此会更小。
2、Picasso也可以指定加载的图片大小:

Picasso.with(mActivity)
.load(Constant.picUrl)
.resize(768, 432)
.into(mIvPic);

但是问题在于你需要主动计算ImageView的大小,或者说你的ImageView大小是具体的值(而不是wrap_content),你也可以这样:

Picasso.with(mActivity)
.load(Constant.picUrl)
.fit()
.centerCrop()
.into(mIvPic);

Image质量细节

ImageView还原到真实大小时,Glide加载的图片没有Picasso那么平滑。

图像和内存

同样将1080 × 1920像素的图片加载到768 × 432ImageView中,Glide加载的图片质量要差于Picasso。这是因为Glide默认的Bitmap格式是RGB-565,比ARGB-8888格式的内存开销大约要小一半。

GIF显示

1、Glide支持GIF显示,而Picasso不支持GIF显示。
2、因为GlideActivity/Fragment的生命周期是一致的,因此GIF动画也会自动的随Activity/Fragment的状态而进行暂停或者重放。Glide缓存在GIF这里也是一样,会调整大小然后缓存。

缓存策略

1、PicassoGlide在磁盘缓存策略上有很大的不同。Picasso缓存的是全尺寸的,而Glide缓存的是跟ImageView尺寸相同的。
2、Picasso只缓存一个全尺寸的,而Glide会为每种大小的ImageView缓存一次。尽管一张图片已经缓存了一次,但是假如你要在另外一个地方再次以不同尺寸显示时还需要重新下载,然后将其调整成新尺寸的大小缓存起来。
3、具体来说就是:假如在第一个页面有一个200 x 200ImageView,在第二个页面有一个100 x 100ImageView,这两个ImageView本来是要显示同一张图片,但是Glide却需要下载两次。
4、可以改变以上这种行为,让Glide既缓存全尺寸又缓存其他尺寸:

Glide.with(this)
.load(Constant.image_dynamic)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivImage);

下次在任何ImageView中加载图片的时候,全尺寸的图片将从缓存中取出重新调整大小,然后进行缓存。

5、Glide的这种缓存方式优点是加载显示非常快,而Picasso的方式则因为需要在显示之前重新调整大小而导致一些延迟,不过GlidePicasso需要更大的空间来进行缓存。

其他

1、包的大小:Picasso(v2.5.1)的大小约118kb,而Glide(v3.5.2)的大小约430kb
2、方法数目:PicassoGlide的方法个数分别是8402678个。对于DEX文件65535个方法限制来说,2678是一个相当大的数字了。建议在使用Glide的时候开启ProGuard
3、Glide可以将任何的本地视频解码成一张静态图片,而Picasso不可以。

Fresco优缺点

FrescoFacebook开源Android平台上一个强大的图片加载库。

主要特点

  1. 两个内存缓存加上Native缓存构成了三级缓存;
  2. 支持流式,可以类似网页上模糊渐进方式显示图片;
  3. 对多帧动画图片支持更好,如:GifWebP等。

内存管理

Fresco最大的亮点在于它的内存管理。Android中的Bitmap占用大量的内存,在Android 5.0以下系统中,这会显著地引发界面卡顿,而使用Fresco将会很好地解决这个问题。Fresco会将图片放到一个特别的内存区域,当图片不再显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM,当APP包含的图片较多时这个效果尤其明显。

图像

Fresco支持图像的渐进式呈现,渐进式的图片格式先呈现大致的图片轮廓,然后随着图片下载的继续,逐渐呈现清晰的图片。这在低网速情况下浏览图片十分有帮助,可以带来更好地用户体验。另外Fresco支持加载GIFWebP格式。

优点

  1. 图片存储在安卓系统的匿名共享内存,而不是虚拟机的堆内存中,图片的中间缓冲数据也存放在本地堆内存。所以应用程序有更多的内存使用,不会因为图片加载而导致OOM,同时也减少垃圾回收器频繁调用回收Bitmap导致的界面卡顿,性能更高;
  2. 渐进式加载JPEG图片,支持图片从模糊到清晰加载;
  3. 图片可以以任意的中心点显示在ImageView,而不仅仅是图片的中心;
  4. JPEG图片改变大小也是在native进行的,不是在虚拟机的堆内存,同样减少OOM的发生;
  5. 很好的支持GIF图片显示。

缺点

  1. 框架较大,影响Apk体积;
  2. 使用较繁琐。

ImageLoader优缺点

比较老的框架、稳定、加载速度适中。

优点

  1. 多线程下载图片,图片可以来源于网络、文件、assets以及drawable中等;
  2. 支持自定义的配置ImageLoader,例如线程池、图片下载器、内存缓存策略、硬盘缓存策略、图片显示选项以及其他的一些配置;
  3. 支持图片的内存缓存、文件系统缓存或者SD卡缓存;
  4. 默认实现多种内存缓存算法,如Size最大先删除、使用最少先删除、最近最少使用先删除、先进先删除、时间最长先删除等;
  5. 支持图片下载过程监听;
  6. 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存;
  7. 较好的控制图片的加载过程,例如暂停图片加载、重新开始加载图片等,一般使用在ListViewGridView中,通过PauseOnScrollListener接口控制滑动过程中暂停加载图片,停止滑动的时候去加载图片;
  8. 提供在较慢的网络下对图片进行加载。

缺点

不支持GIF图片加载,使用稍微繁琐,并且缓存机制没有和Http的缓存很好的结合,完全是自己的一套缓存机制。

Picasso优缺点

使用方便、一行代码完成加载图片并显示、框架体积小。

优点

  1. 自带统计检测功能:支持图片缓存使用检测,包括:缓存命中率、已使用内存大小、节省的流量等;
  2. 支持优先级处理:每次任务调度前会选择优先级高的任务,比如App页面中Banner的优先级高于Icon时就很适用;
  3. 支持延迟到图片尺寸计算完成加载;
  4. 支持飞行模式、并发线程数根据网络状态变化:手机切换到飞行模式或网络状态变换时会自动调整线程池最大并发数;
  5. “无”本地缓存:无”本地缓存不是说没有本地缓存,而是Picasso自己没有实现,交给了Square的另外一个网络库OkHttp去实现。这样的好处是可以通过请求Response Header中的Cache-ControlExpired来控制图片的过期时间。

缺点

不支持GIF,缓存图片是未缩放的,默认使用ARGB_8888格式缓存图片,缓存体积大。

Glide优缺点

优点

  1. 图片占用内存回收及时,能减少因内存不足造成的崩溃,生命周期和Activity/Fragment一致;
  2. 默认Bitmap格式是RGB_565,减少内存资源占用;
  3. GlideUniversal-Image-Loader占用的内存要小一些;
  4. 图片显示效果为渐变,更加平滑;
  5. Glide可以将任何的本地视频解码成一张静态图片;
  6. 支持GifWebP、缩略图等。

缺点

框架较大,影响Apk体积。

项目地址 ☞ 传送门