简介
Picasso
是Square
公司开源的一个Android
图形缓存库,可以实现图片下载和缓存功能。
主要有以下一些特性:
- 在
Adapter
中回收和取消已经不在视野范围图片资源的加载,防止可能出现的图片错位; - 使用复杂的图片压缩转换来尽可能的减少内存消耗;
- 使用最少的内存完成复杂的图形转换操作;
- 自带内存和硬盘缓存;
- 可加载网络或本地资源。
GitHub
地址:
背景
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()
:
为请求添加标记提升用户体验。比如在列表ListView
的Item
中加载了图片,当用户在快速滑动的时候可以设置停止请求,在滑动停止时再去加载请求,退出当前页面时取消请求。
Picasso
提供了三种设置Tag
的方式:
- 暂停标记:
pauseTag()
- 可见标记:
resumeTag()
- 取消标记:
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
默认的缓存分配大小特点:
-
LRU
缓存占应用程序可用内存的15%
; - 本地缓存占硬盘空间的
2%
,但不超过50M
且不小于5M
(前提是这种情况只在4.0
以上有效果或者你能像OKHttp
那样提供一个本地缓存库来支持全平台); -
Picasso
默认开启3
个线程来进行本地与网络之间的访问; -
Picasso
加载图片顺序为内存–>本地–>网络。
22. 内存策略:
MemoryPolicy
负责管理内存缓存,可能有的时候你不想让Picasso
去内存中进行读取而跳过此步骤,此时你可以在进行网络请求的时候调用memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional)
方法。MemoryPolicy
是一个枚举类型,只有两个值:NO_CACHE
和NO_STORE
。
-
NO_CACHE
:让Picasso
跳过从内存中读取图片这一操作; -
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
负责管理本地缓存,它也是一个枚举类型。
-
NO_CACHE
:跳过从本地读取资源这一过程; -
NO_STORE
:不进行本地图片缓存; -
OFFLINE
:加载图片的时候只从本地读取,除非网络正常且本地找不到资源的情况下。
示例代码:
Picasso.with(mActivity)
.load(Constant.picUrl)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(mIvNetworkPictures);
24. 缓存指示器,查看图片来源于何处:
当我们想知道所加载的图片来源于何处,是内存、本地还是从网络加载的时候,只需要在请求的时候调用.setIndicatorsEnabled(true)
方法就好了。
Picasso.with(mActivity)
.setIndicatorsEnabled(true);
这样每张图片在显示的时候,左上角都会有一个小标记,分别是蓝色、绿色、红色三种颜色。
- 蓝色:从内存中获取,性能最佳;
- 绿色:从本地获取,性能一般;
- 红色:从网络加载,性能最差。
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-Control
及Expired
控制图片的过期时间。
自定义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);
Glide
与Picasso
比较
使用方法
1、Glide
更容易使用,因为Glide
的with()
方法不光接受Context
,还能接受Activity
和Fragment
,Context
会自动从它们获取。Picasso
只接受Context
。
2、将Activity/Fragment
作为with()
参数的好处是图片加载将会和Activity/Fragment
的生命周期保持一致。比如在onPause
状态暂停加载,在onResume
状态的时候又自动重新加载。
默认Bitmap
格式
1、Glide
默认Bitmap
格式是RGB_565
,Picasso
默认的Bitmap
格式的是ARGB_8888
。
2、想要提高Glide
的图片效果,Glide
可以创建一个新的GlideModule
将Bitmap
格式转换为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 × 432
的ImageView
中,Glide
加载的图片质量要差于Picasso
。这是因为Glide
默认的Bitmap
格式是RGB-565
,比ARGB-8888
格式的内存开销大约要小一半。
GIF
显示
1、Glide
支持GIF
显示,而Picasso
不支持GIF
显示。
2、因为Glide
和Activity/Fragment
的生命周期是一致的,因此GIF
动画也会自动的随Activity/Fragment
的状态而进行暂停或者重放。Glide
缓存在GIF
这里也是一样,会调整大小然后缓存。
缓存策略
1、Picasso
和Glide
在磁盘缓存策略上有很大的不同。Picasso
缓存的是全尺寸的,而Glide
缓存的是跟ImageView
尺寸相同的。
2、Picasso
只缓存一个全尺寸的,而Glide
会为每种大小的ImageView
缓存一次。尽管一张图片已经缓存了一次,但是假如你要在另外一个地方再次以不同尺寸显示时还需要重新下载,然后将其调整成新尺寸的大小缓存起来。
3、具体来说就是:假如在第一个页面有一个200 x 200
的ImageView
,在第二个页面有一个100 x 100
的ImageView
,这两个ImageView
本来是要显示同一张图片,但是Glide
却需要下载两次。
4、可以改变以上这种行为,让Glide
既缓存全尺寸又缓存其他尺寸:
Glide.with(this)
.load(Constant.image_dynamic)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivImage);
下次在任何ImageView
中加载图片的时候,全尺寸的图片将从缓存中取出重新调整大小,然后进行缓存。
5、Glide
的这种缓存方式优点是加载显示非常快,而Picasso
的方式则因为需要在显示之前重新调整大小而导致一些延迟,不过Glide
比Picasso
需要更大的空间来进行缓存。
其他
1、包的大小:Picasso(v2.5.1)
的大小约118kb
,而Glide(v3.5.2)
的大小约430kb
。
2、方法数目:Picasso
和Glide
的方法个数分别是840
和2678
个。对于DEX
文件65535
个方法限制来说,2678
是一个相当大的数字了。建议在使用Glide
的时候开启ProGuard
。
3、Glide
可以将任何的本地视频解码成一张静态图片,而Picasso
不可以。
Fresco
优缺点
Fresco
是Facebook
开源Android
平台上一个强大的图片加载库。
主要特点
- 两个内存缓存加上
Native
缓存构成了三级缓存; - 支持流式,可以类似网页上模糊渐进方式显示图片;
- 对多帧动画图片支持更好,如:
Gif
、WebP
等。
内存管理
Fresco
最大的亮点在于它的内存管理。Android
中的Bitmap
占用大量的内存,在Android 5.0
以下系统中,这会显著地引发界面卡顿,而使用Fresco
将会很好地解决这个问题。Fresco
会将图片放到一个特别的内存区域,当图片不再显示的时候,占用的内存会自动被释放。这会使得APP
更加流畅,减少因图片内存占用而引发的OOM
,当APP
包含的图片较多时这个效果尤其明显。
图像
Fresco
支持图像的渐进式呈现,渐进式的图片格式先呈现大致的图片轮廓,然后随着图片下载的继续,逐渐呈现清晰的图片。这在低网速情况下浏览图片十分有帮助,可以带来更好地用户体验。另外Fresco
支持加载GIF
、WebP
格式。
优点
- 图片存储在安卓系统的匿名共享内存,而不是虚拟机的堆内存中,图片的中间缓冲数据也存放在本地堆内存。所以应用程序有更多的内存使用,不会因为图片加载而导致
OOM
,同时也减少垃圾回收器频繁调用回收Bitmap
导致的界面卡顿,性能更高; - 渐进式加载
JPEG
图片,支持图片从模糊到清晰加载; - 图片可以以任意的中心点显示在
ImageView
,而不仅仅是图片的中心; -
JPEG
图片改变大小也是在native
进行的,不是在虚拟机的堆内存,同样减少OOM
的发生; - 很好的支持
GIF
图片显示。
缺点
- 框架较大,影响
Apk
体积; - 使用较繁琐。
ImageLoader
优缺点
比较老的框架、稳定、加载速度适中。
优点
- 多线程下载图片,图片可以来源于网络、文件、
assets
以及drawable
中等; - 支持自定义的配置
ImageLoader
,例如线程池、图片下载器、内存缓存策略、硬盘缓存策略、图片显示选项以及其他的一些配置; - 支持图片的内存缓存、文件系统缓存或者
SD
卡缓存; - 默认实现多种内存缓存算法,如
Size
最大先删除、使用最少先删除、最近最少使用先删除、先进先删除、时间最长先删除等; - 支持图片下载过程监听;
- 根据控件
(ImageView)
的大小对Bitmap
进行裁剪,减少Bitmap
占用过多的内存; - 较好的控制图片的加载过程,例如暂停图片加载、重新开始加载图片等,一般使用在
ListView
、GridView
中,通过PauseOnScrollListener
接口控制滑动过程中暂停加载图片,停止滑动的时候去加载图片; - 提供在较慢的网络下对图片进行加载。
缺点
不支持GIF
图片加载,使用稍微繁琐,并且缓存机制没有和Http
的缓存很好的结合,完全是自己的一套缓存机制。
Picasso
优缺点
使用方便、一行代码完成加载图片并显示、框架体积小。
优点
- 自带统计检测功能:支持图片缓存使用检测,包括:缓存命中率、已使用内存大小、节省的流量等;
- 支持优先级处理:每次任务调度前会选择优先级高的任务,比如
App
页面中Banner
的优先级高于Icon
时就很适用; - 支持延迟到图片尺寸计算完成加载;
- 支持飞行模式、并发线程数根据网络状态变化:手机切换到飞行模式或网络状态变换时会自动调整线程池最大并发数;
- “无”本地缓存:无”本地缓存不是说没有本地缓存,而是
Picasso
自己没有实现,交给了Square
的另外一个网络库OkHttp
去实现。这样的好处是可以通过请求Response Header
中的Cache-Control
及Expired
来控制图片的过期时间。
缺点
不支持GIF
,缓存图片是未缩放的,默认使用ARGB_8888
格式缓存图片,缓存体积大。
Glide
优缺点
优点
- 图片占用内存回收及时,能减少因内存不足造成的崩溃,生命周期和
Activity/Fragment
一致; - 默认
Bitmap
格式是RGB_565
,减少内存资源占用; -
Glide
比Universal-Image-Loader
占用的内存要小一些; - 图片显示效果为渐变,更加平滑;
-
Glide
可以将任何的本地视频解码成一张静态图片; - 支持
Gif
、WebP
、缩略图等。
缺点
框架较大,影响Apk
体积。
项目地址 ☞ 传送门