核心流程(所有方法都遵循)
无论使用哪种库,加载网络图片的基本步骤都是一样的:

- 获取网络图片的 URL:一个指向图片文件的字符串地址。
- 发起异步网络请求:在后台线程(如子线程或线程池)中,通过 URL 获取图片的输入流(
InputStream)。 - 解码输入流:将获取到的
InputStream解码成 Android 可以识别的Bitmap对象。 - 在主线程更新 UI:将解码后的
Bitmap对象设置到ImageView控件上,以显示在屏幕上。
使用 AsyncTask (已过时,但有助于理解原理)
AsyncTask 是早期 Android 提供的用于在后台执行耗时操作并在主线程更新 UI 的工具类,虽然现在已被标记为过时,但它很好地展示了加载图片的基本原理。
public class ImageLoadTask extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
// 构造函数,传入要显示图片的 ImageView
public ImageLoadTask(ImageView imageView) {
this.imageView = imageView;
}
// 在后台线程执行,耗时操作(网络请求、解码)都在这里
@Override
protected Bitmap doInBackground(String... urls) {
String imageUrl = urls[0];
Bitmap bitmap = null;
try {
// 1. 创建 URL 对象
URL url = new URL(imageUrl);
// 2. 打开连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
// 3. 获取输入流
InputStream inputStream = connection.getInputStream();
// 4. 将输入流解码为 Bitmap
bitmap = BitmapFactory.decodeStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap; // 返回结果,会传递到 onPostExecute
}
// 在主线程执行,doInBackground 执行完后调用
@Override
protected void onPostExecute(Bitmap bitmap) {
if (bitmap != null && imageView != null) {
// 5. 在 UI 线程更新 ImageView
imageView.setImageBitmap(bitmap);
}
}
}
// 使用方式
ImageView myImageView = findViewById(R.id.my_image_view);
String imageUrl = "https://example.com/path/to/image.jpg";
new ImageLoadTask(myImageView).execute(imageUrl);
缺点:
- 容易导致内存泄漏(Activity 在任务完成前销毁)。
- 串行执行,效率不高。
- 处理配置变更(如屏幕旋转)时比较麻烦。
- 已过时,不推荐在新项目中使用。
使用第三方库 (强烈推荐)
手动管理网络请求和图片缓存非常复杂,容易出错,社区和 Google 推荐使用成熟的第三方库来简化开发。
Glide (Google 推荐)
Glide 是 Google 官方推荐的图片加载库,以其流畅的动画、出色的性能和简洁的 API 而闻名。

添加依赖
在 app/build.gradle 文件中添加:
dependencies {
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
}
使用 代码极其简洁:
ImageView imageView = findViewById(R.id.my_image_view);
String imageUrl = "https://example.com/path/to/image.jpg";
// 基本用法
Glide.with(this) // 传入 Activity, Fragment, 或 Context
.load(imageUrl) // 加载图片 URL
.into(imageView); // 设置到 ImageView
Glide 的优点:
- 自动缓存:内存缓存和磁盘缓存都自动处理,极大提升加载速度和用户体验。
- 生命周期集成:自动感知 Activity/Fragment 的生命周期,在销毁时自动取消请求,避免内存泄漏。
- 支持多种数据源:除了 URL,还可以加载
File,Uri,byte[]等。 - 强大的 API:支持图片变换(如圆角、裁剪)、过渡动画、占位符、错误图等。
- 高性能:高效的图片解码和内存管理。
Picasso (Square 出品)
Picasso 是另一个非常流行的图片加载库,由著名的 Square 公司开发,它的 API 同样非常简洁。

添加依赖
在 app/build.gradle 文件中添加:
dependencies {
implementation 'com.squareup.picasso:picasso:2.8'
}
使用
ImageView imageView = findViewById(R.id.my_image_view);
String imageUrl = "https://example.com/path/to/image.jpg";
Picasso.get()
.load(imageUrl)
.into(imageView);
Picasso 的优点:
- API 极其简洁,易于上手。
- 自动处理缓存和线程。
- 会在后台线程自动对图片进行二次采样,有效避免
OutOfMemoryError。
Picasso 与 Glide 的对比:
- Glide 在功能上更全面,尤其是在动画、缓存策略和加载本地资源方面更灵活,是 Google 的首选。
- Picasso 的 API 可能更“经典”一些,但近年来更新较慢,功能相对固定。
- 对于新项目,Glide 通常是更推荐的选择。
使用 Android Jetpack 的 Coil (现代新选择)
Coil 是一个新兴的、非常现代化的图片加载库,全称是 "Coroutines Image Loader",它充分利用了 Kotlin 的协程,代码非常简洁和高效。
添加依赖
在 app/build.gradle 文件中添加:
dependencies {
implementation "io.coil-kt:coil:2.5.0"
}
使用 由于基于协程,用法稍有不同,但依然非常优雅:
// 在 Activity 或 Fragment 中
ImageView imageView = findViewById(R.id.my_image_view);
String imageUrl = "https://example.com/path/to/image.jpg";
// 使用 lifecycleScope 启动一个协程
lifecycleScope.launch {
try {
// Coil 会自动处理所有事情
val bitmap = Coil.get(imageView.context) {
data(imageUrl)
target(imageView) // 直接设置目标
}
// 或者更简单的方式
// Coil.load(imageView.context, imageUrl).into(imageView);
} catch (e: Exception) {
// 处理错误
}
}
Coil 的优点:
- 极致简洁:API 设计非常现代化,代码量少。
- 基于协程:性能更好,代码更易于理解,避免了回调地狱。
- 轻量级:依赖库非常小。
- Kotlin 原生支持:与 Kotlin 生态无缝集成。
- 性能优秀:在启动速度和内存占用方面有不错的表现。
最佳实践与注意事项
- 永远不要在主线程做网络或 IO 操作:这是 Android 开发的铁律。
- 使用成熟的库:除非有特殊需求,否则强烈建议使用 Glide、Coil 或 Picasso,它们已经解决了缓存、内存管理、生命周期等所有棘手问题。
- 处理内存缓存:库通常会自动处理,但了解其原理很重要,内存缓存使用
LruCache等策略,当内存紧张时会自动移除不常用的图片。 - 处理磁盘缓存:将下载的图片保存到本地,这样即使没有网络也能快速显示,库同样会自动处理。
- 处理图片尺寸:直接加载原图到内存可能会导致
OutOfMemoryError,现代库(如 Glide)会自动根据ImageView的尺寸对图片进行二次采样,减小内存占用。 - 添加占位符和错误图:提升用户体验,在加载过程中显示一个占位图,加载失败时显示一个错误图。
// Glide 示例 Glide.with(this) .load(imageUrl) .placeholder(R.drawable.placeholder) // 占位图 .error(R.drawable.error_image) // 错误图 .into(imageView);
| 方法 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|
AsyncTask |
原理简单,适合学习 | 已过时,易出bug,性能差 | ⭐ (仅用于学习) |
| Glide | 功能强大,Google推荐,生态完善 | 相对Picasso稍大 | ⭐⭐⭐⭐⭐ (首选) |
