Android 图片加载之浅谈 Glide

文章目录
  1. 1. 简介 Glide
  2. 2. Demo 用法
  3. 3. OOM 优化方案
  4. 4. 参考文献

Learn something of everything, learn everything of something.

前面谈了老牌图片加载框架 Universal Image Loader,这期谈一下当前流行的 Glide,这是 Google 推荐使用的图片加载框架,其在大多数情况下,一行代码就能搞定图片加载,下面详细来看。

简介 Glide

Glide 是 Android 上一个快速高效的开源多媒体管理和图像加载框架,其提供了简单易用的 API,包括多媒体解码、内存和磁盘缓存,与资源池技术。此外,Glide 支持拉取、解码和显示视频快照、图像和 GIF 动画。Glide 如此灵活以至于允许开发者植入几乎任何网络栈。默认时,Glide 使用的是自定义的栈,其基于 HttpUrlConnection,也提供了 Google Volley 或 Square OkHttp 集成的工具库。

Glide 基础的目标是,让任何种类图像列表的滚动,变得尽可能的顺滑和快速,此外,其几乎在任何需要拉取、缩放和展示远程图像的情况下,都很高效。

以上来自 GitHub

Demo 用法

Demo 地址:GlideDemo

引入 Gradle 依赖

1
2
compile 'com.github.bumptech.glide:glide:4.2.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.2.0'

Android Manifest:

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

MainActivity 类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainActivity extends AppCompatActivity {

private ImageView mImageView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_picture);

String url = "http://img.my.csdn.net/uploads/201309/01/1378037194_2965.jpg";
Glide.with(this).load(url).into(mImageView);
}

}

布局文件同样也很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">


<ImageView
android:id="@+id/iv_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher"/>

</FrameLayout>

运行程序如下:

核心代码就一行:

1
Glide.with(this).load(url).into(mImageView);

Glide.with() 创建一个加载图片的实例,with() 里可传入 Context、Activity 或 Fragment 类型的参数。Activity 或 Fragment 里,可直接传入 this;调用处不在 Activity 和 Fragment 中时,则可传入 ApplicationContext。需要注意的是,with() 中传入的实例决定 Glide 加载图片的生命周期,若其对应的实例对象销毁掉,则停止图片加载。

load() 中传入指定的图片资源,其支持加载网络图片、本地图片、资源图像、二进制流和 Uri 对象等,举例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 本地图片
File file = new File(getExternalCacheDir() + "/image.jpg");
Glide.with(this).load(file).into(mImageView);

// 资源图像
int resource = R.drawable.image;
Glide.with(this).load(resource).into(mImageView);

// 二进制流
byte[] images = getImageBytes();
Glide.with(this).load(images).into(mImageView);

// Uri 对象
Uri uri = getImageUri();
Glide.with(this).load(uri).into(mImageView);

最后,into() 中传入指定的 ImageView。

占位符

由于从网络上下载图片需要一定的时间,加载网络图片时,会先出现空白,然后一会儿,图片才显示出来。这样会影响用户体验,这里,Glide 提供了占位符功能。占位符即正在执行请求时展示的图像,若请求成功,则占位符会被请求到的资源替换,注意的是,若被请求的资源是从内存中加载出来的,则占位符或许不会显示。添加占位符代码如下:

1
2
3
4
5
Glide.with(this)
.load(url)
.apply(new RequestOptions()
.placeholder(R.drawable.ic_load))
.into(mImageView);

运行,则会先出现一张默认的占位符图片,被请求的图片加载完成后,会替换掉占位符显示出来。

接下来,看 error 占位符,即出现异常情况导致图片加载失败,如网络异常等。代码如下:

1
2
3
4
5
6
7
Glide.with(this)
.load(url)
.apply(new RequestOptions()
.placeholder(R.drawable.ic_load))
.apply(new RequestOptions()
.error(R.drawable.ic_load_fail))
.into(mImageView);

注释掉 AndroidManifest.xml 中的网络权限,运行显示设置好的 error 图片。

最后,看 fallback 占位符,其在请求的 url/model 为 null 时展示。默认情况下,Glide 将 null 作为错误处理,但是,null 为可接受的正常情况时,如某个 null 的个人资料 url 意指该用户未设置头像,应使用默认的头像。

详情参见官方文档及其翻译–占位符.

图像格式

Glide 支持加载 GIF 动画,其内部会自动判断图像格式,如给定一 GIF 动画的 URL 地址如下:

1
http://i.dimg.cc/61/a1/f0/6b/e9/be/3f/f1/f4/f8/4c/65/3c/63/b5/a2.gif

替换掉原先的 URL 地址,运行如下:

若要指定加载的图片为静态图,则可以使用 asBitmap() 方法:

1
2
3
4
5
String url = "http://i.dimg.cc/61/a1/f0/6b/e9/be/3f/f1/f4/f8/4c/65/3c/63/b5/a2.gif";
Glide.with(this)
.asBitmap()
.load(url)
.into(mImageView);

运行如下:

即只显示 GIF 图的第一帧图片。

更多参见官方文档及其翻译– Generated API

图像大小

大多数情况下,使用 Glide 无需指定图片的大小。Glide 不会将图片的完整尺寸加载进内存中,比如,给定一张图片的大小是 800X800 像素,然而,设定的 ImageView 大小为 100X100 像素,Glide 会判定指定 ImageView 的大小,将相应的图片像素加载进内存中,以节省内存开销。

此外,Glide 支持对给定图片指定一个大小,如指定为 200X200,则链式调用如下:

1
2
3
4
5
6
Glide.with(this)
.asBitmap()
.load(url)
.apply(new RequestOptions()
.override(200, 200))
.into(mImageView);

OOM 优化方案

可以判定的是,几乎所有的 OOM 错误都是宿主应用自身的问题,应用里两种常见的 OOM 错误即:

  • 过大的内存分配

举个例子,若打开一个单独页面或加载一个单独图片造成了 OOM,则很有可能是在加载一个过大的图。

我们要明确的是,使用 Bitmap 显示一张图片需要的内存数量为:

1
图片的宽度 X 图片的高度 X 每像素字节数

其中,每像素字节数由显示图片的 Bitmap.Config 决定,通常于 ARGB_8888 的位图来说,1 个像素为 4 个字节。图片越大,需要的内存就越多,如一个 12M 的图片需要的内存为 48M。

Glide 则会将图片自动 downsample,其基于 Target、ImageView 或调用 override() 方法设定的尺寸,要解决过大的内存分配避免使用 Target.SIZE_ORIGINAL,同时,确保 ImageView 的尺寸或调用 override() 方法设定的尺寸是最为合理的

  • 内存泄漏

有这样一种情况,若应用中持续重复特定步骤,会逐渐增加应用的内存开销并导致 OOM,则可能会有内存泄漏。参见 Android 官方文档 View the Java Heap and Memory Allocations with Memory Profiler 追踪和调试内存的使用信息。比如,需要对已销毁的 Fragment 或 Activity 在生命周期的合适时机,移除对其的引用,以免持有过多的对象。

更多详情参见官方文档及其翻译–调试

至此,浅谈 Glide 到此结束,后来接着一期将从源码角度探究这一新兴的贵族。

本人才疏学浅,如有疏漏错误之处,望读者中有识之士不吝赐教,谢谢。

1
Email: [email protected] / WeChat: Wolverine623

您也可以关注我个人的微信公众号码农六哥第一时间获得博客的更新通知,或后台留言与我交流

参考文献

1.https://github.com/bumptech/glide

2.http://blog.csdn.net/guolin_blog/article/details/53759439