核心原理
无论使用哪种方法,其基本原理都是相同的:

- 网络请求:在 Android 应用中,通过 HTTP/HTTPS 协议向服务器发送一个请求,获取图片的 URL。
- 下载图片:服务器返回图片的二进制数据(流或字节数组)。
- 解码与显示:将下载到的二进制数据解码成 Android 可以识别的
Bitmap对象。 - 渲染到 UI:将
Bitmap对象设置到ImageView控件上进行显示。
使用 Glide (强烈推荐)
Glide 是 Google 推荐的一个图片加载和缓存库,它以其简洁的 API、强大的性能和自动管理缓存而闻名,对于大多数应用来说,这是首选方案。
添加依赖
在你的 app 模块的 build.gradle.kts (或 build.gradle) 文件中添加 Glide 的依赖:
// build.gradle.kts (Kotlin DSL)
dependencies {
implementation("com.github.bumptech.glide:glide:4.16.0")
kapt("com.github.bumptech.glide:compiler:4.16.0")
}
// build.gradle (Groovy DSL)
dependencies {
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
}
添加网络权限
在 app/src/main/AndroidManifest.xml 文件中添加网络访问权限:
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
...
</application>
</manifest>
在布局文件中添加 ImageView
<!-- activity_main.xml -->
<ImageView
android:id="@+id/my_image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:scaleType="centerCrop" />
在 Activity 或 Fragment 中加载图片
// MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 图片的 URL,请替换成你自己的
val imageUrl = "https://example.com/path/to/your/image.jpg"
// 使用 Glide 加载图片
Glide.with(this)
.load(imageUrl) // 加载的图片 URL
.apply(
RequestOptions()
.placeholder(R.drawable.placeholder_image) // 加载中的占位图
.error(R.drawable.error_image) // 加载失败时的错误图
.override(800, 800) // 指定图片的显示尺寸
)
.into(my_image_view) // 目标 ImageView
}
}
Glide 的优点:

- 简洁:API 非常简单,一行代码即可完成加载。
- 性能高:使用
BitmapPool复用位图,减少 GC 压力。 - 自动缓存:自动处理内存缓存和磁盘缓存,避免重复下载。
- 支持多种数据源:除了 URL,还可以加载
File,Uri,byte[]等。 - 支持动画和变换:可以轻松实现图片的淡入淡出、圆形、圆角等效果。
使用 Coil (现代、轻量级)
Coil 是一个由 Square 公司开发的、基于 Kotlin 协程的图片加载库,它现代、快速、轻量级,并且与 Jetpack Compose 集成得非常好。
添加依赖
在 build.gradle.kts (或 build.gradle) 中添加 Coil 的依赖:
// build.gradle.kts (Kotlin DSL)
dependencies {
implementation("io.coil-kt:coil:2.5.0")
}
// build.gradle (Groovy DSL)
dependencies {
implementation 'io.coil-kt:coil:2.5.0'
}
添加网络权限 (同 Glide)
在 Activity 或 Fragment 中加载图片
// MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import coil.load
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val imageUrl = "https://example.com/path/to/your/image.jpg"
// 使用 Coil 加载图片
my_image_view.load(imageUrl) {
// 占位图
placeholder(R.drawable.placeholder_image)
// 错误图
error(R.drawable.error_image)
// 跨域配置 (如果需要)
crossfade(true) // 淡入淡出效果
}
}
}
Coil 的优点:
- 现代:基于 Kotlin 协程,代码更简洁,无回调地狱。
- 轻量:APM 体积比 Glide 小。
- 性能好:同样支持高效的缓存和内存管理。
- Jetpack Compose 友好:是 Compose 官方推荐的图片加载库。
使用原生 Kotlinx Coroutines + OkHttp + Glide 的解码器
这是一种更底层的实现方式,适用于需要高度自定义网络请求逻辑的场景,我们可以使用 OkHttp 发起网络请求,然后将流交给 Glide 的 ByteBufferDecoder 来处理。

添加依赖
// build.gradle.kts (Kotlin DSL)
dependencies {
// OkHttp for networking
implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Glide for image loading and caching
implementation("com.github.bumptech.glide:glide:4.16.0")
kapt("com.github.bumptech.glide:compiler:4.16.0")
// Coroutines for asynchronous operations
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
}
创建一个自定义的 Glide 模块
// MyGlideModule.kt
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.module.AppGlideModule
@GlideModule
class MyGlideModule : AppGlideModule() {
// 可以在这里配置 Glide 的全局选项
}
在 ViewModel 或 Repository 中处理网络请求
// MyViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.InputStream
class MyViewModel : ViewModel() {
private val _imageStream = MutableStateFlow<InputStream?>(null)
val imageStream: StateFlow<InputStream?> = _imageStream
private val okHttpClient = OkHttpClient()
fun loadImageFromServer(imageUrl: String) {
viewModelScope.launch(Dispatchers.IO) {
try {
val request = Request.Builder()
.url(imageUrl)
.build()
val response = okHttpClient.newCall(request).execute()
if (response.isSuccessful) {
val inputStream = response.body?.byteStream()
_imageStream.value = inputStream
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
在 Activity/Fragment 中使用 Glide 加载流
// MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.viewModels
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val imageUrl = "https://example.com/path/to/your/image.jpg"
viewModel.loadImageFromServer(imageUrl)
// 观察 StateFlow 并使用 Glide 加载输入流
viewModel.imageStream.observe(this) { inputStream ->
inputStream?.let {
Glide.with(this)
.load(it) // 直接加载 InputStream
.into(my_image_view)
}
}
}
}
这种方式的优点:
- 完全控制:你可以完全自定义网络请求头、超时、重试逻辑等。
- 解耦:网络逻辑和 UI 显示逻辑分离,更符合 MVVM 架构。
重要注意事项
主线程 (UI Thread) 问题
网络请求和耗时操作(如图片解码)绝对不能在主线程上执行,否则会导致应用卡顿甚至 ANR (Application Not Responding)。
- 传统方式:需要在子线程中执行网络请求,然后通过
runOnUiThread或Handler将结果传回主线程更新 UI。 - 现代方式 (Glide/Coil):它们内部已经处理好了线程切换,你只需要在主线程(如
Activity/Fragment的onCreate中)调用它们的 API 即可,它们会自动在后台线程加载图片,并在加载完成后自动在主线程更新ImageView。
权限声明
从 Android 9 (API 28) 开始,默认情况下,App 只能通过 HTTPS 加载网络资源,如果你的服务器图片是 HTTP 协议的,需要在 AndroidManifest.xml 中添加 usesCleartextTraffic 标志:
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
最佳实践是让服务器支持 HTTPS。
内存优化
图片,尤其是高分辨率的图片,会占用大量内存,直接加载原图可能会导致 OutOfMemoryError。
- 采样:在加载时告诉
Glide或Coil你期望的显示尺寸,它们会自动对图片进行采样,只解码屏幕需要的部分,大大减少内存占用。- Glide:
.override(width, height) - Coil:
.size(width, height)
- Glide:
- 回收:当
ImageView被回收或不再需要显示图片时(例如在RecyclerView的onViewRecycled中),应调用Glide.with(context).clear(view)或view.clearImage()来释放资源。
总结与推荐
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Glide | 功能强大,稳定,API丰富,社区成熟 | 相对较重,Kotlin支持不是第一方 | 大多数 Android 应用,尤其是需要复杂图片处理(如GIF、WebP)的场景。 |
| Coil | 现代轻量,基于Kotlin协程,与Compose集成好 | 相对较新,生态系统不如Glide | 新项目,特别是使用Kotlin和Jetpack Compose的项目。 |
| 原生+自定义 | 灵活性最高,可完全控制网络层 | 代码复杂,需要自己处理线程、缓存、错误等 | 需要高度定制网络逻辑的特殊项目,或者作为学习底层原理的实践。 |
对于绝大多数开发者,我强烈推荐从 Glide 或 Coil 开始。 它们能让你用最少的代码实现最稳定、最高效的功能,让你专注于业务逻辑本身,而不是重复造轮子,如果你是新手,Glide 是一个非常稳妥的选择,如果你在拥抱 Kotlin 和 Jetpack 生态,Coil 会给你带来更好的开发体验。
