- 基础方案:使用
HttpURLConnection和AsyncTask(适用于较旧的 Android 版本,有助于理解原理)。 - 现代方案:使用现代库(如 Kotlin Coroutines + Retrofit + Glide),这是目前 Android 开发的主流和推荐方式。
- 权限:讨论网络权限。
- 错误处理与最佳实践:包括线程安全、内存优化、错误处理等。
基础实现(HttpURLConnection + AsyncTask)
这种方式不依赖第三方库,适合理解底层原理,但在新项目中不推荐。

添加网络权限
在 AndroidManifest.xml 文件中,必须添加访问网络的权限:
<manifest ...>
<!-- 允许应用访问网络 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Android 9 (API 28) 及以上默认禁止 HTTP,允许 HTTPS -->
<application
android:usesCleartextTraffic="true"
...>
...
</application>
</manifest>
创建下载任务
AsyncTask 可以在后台线程执行网络请求,并在完成后在主线程更新 UI。
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
// 用于显示下载的图片的 ImageView
private final ImageView imageView;
public DownloadImageTask(ImageView imageView) {
this.imageView = imageView;
}
// 在后台线程执行,执行耗时操作
@Override
protected Bitmap doInBackground(String... urls) {
String imageUrl = urls[0];
Bitmap bitmap = null;
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap; // 返回结果给 onPostExecute
}
// 在主线程执行,用于更新 UI
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
在 Activity 或 Fragment 中使用
ImageView myImageView = findViewById(R.id.my_image_view); String imageUrl = "https://example.com/path/to/your/image.jpg"; // 创建并执行 AsyncTask new DownloadImageTask(myImageView).execute(imageUrl);
缺点:
AsyncTask在 Android 11 (API 30) 中已被标记为过时。- 处理并发、取消任务等场景比较复杂。
- 容易发生内存泄漏,Activity 在任务完成前销毁。
现代实现(Kotlin Coroutines + Retrofit + Glide)
这是目前 Android 开发最推荐、最简洁、最强大的方式,我们将使用 Kotlin 来演示。

添加依赖
在 app/build.gradle.kts (或 build.gradle) 文件中添加必要的库:
// 对于 Kotlin 项目
dependencies {
// Kotlin Coroutines (用于异步操作)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// Retrofit (用于进行网络请求)
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0") // 如果你还需要解析 JSON
// Glide (用于加载和显示图片,支持缓存、生命周期管理等)
implementation("com.github.bumptech.glide:glide:4.16.0")
kapt("com.github.bumptech.glide:compiler:4.16.0") // 用于注解处理器
}
添加网络权限
同方案一,确保 AndroidManifest.xml 中有 INTERNET 权限。
使用 Glide 直接加载(最简单的方式)
Glide 内部已经处理了所有复杂的操作:后台下载、缓存、线程管理、生命周期绑定等,你只需要一行代码。
在 Activity 或 Fragment 中:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_main.*
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"
// 使用 Glide 加载图片
Glide.with(this) // 上下文
.load(imageUrl) // 图片 URL
.into(myImageView) // 目标 ImageView
}
}
就这么简单! Glide 会自动:
- 在后台线程下载图片。
- 将图片显示在
myImageView上。 - 处理图片的缓存(内存和磁盘),避免重复下载。
- 当
Activity或Fragment销毁时,自动取消加载任务,防止内存泄漏。
使用 Retrofit + Coroutines 获取图片 URL
如果你的图片 URL 是从 API 的 JSON 响应中获取的,那么使用 Retrofit 来获取这个 URL,然后再用 Glide 显示。
a. 定义数据模型
// 假设 API 返回的 JSON 是这样的:
// { "imageUrl": "https://example.com/image.jpg", "title": "My Image" }
data class ImageResponse(
val imageUrl: String,
val title: String
)
b. 创建 Retrofit API 接口
import retrofit2.http.GET
interface ApiService {
@GET("api/get_image_info") // 你的 API 端点
suspend fun getImageInfo(): ImageResponse // 使用 suspend 关键字
}
c. 在 ViewModel 中调用
ViewModel 是管理 UI 数据和业务逻辑的最佳场所。
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class MyViewModel : ViewModel() {
private val apiService: ApiService by lazy {
// 创建 Retrofit 实例
Retrofit.Builder()
.baseUrl("https://your-api-base-url.com/") // 你的 API 基础 URL
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
fun fetchAndDisplayImage(imageView: ImageView) {
viewModelScope.launch { // viewModelScope 会自动在 ViewModel 销毁时取消协程
try {
val imageResponse = apiService.getImageInfo()
// 获取到 URL 后,用 Glide 显示
Glide.with(imageView.context)
.load(imageResponse.imageUrl)
.into(imageView)
} catch (e: Exception) {
// 处理网络错误或解析错误
e.printStackTrace()
// 可以在这里更新 UI 显示错误信息
}
}
}
}
d. 在 Activity/Fragment 中使用 ViewModel
class MainActivity : AppCompatActivity() {
private lateinit var myViewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
myViewModel.fetchAndDisplayImage(myImageView)
}
}
核心概念与最佳实践
权限(Permissions)
INTERNET:从 Android 9 (API 28) 开始,默认禁止使用 HTTP 协议,只允许 HTTPS,如果你的服务器使用 HTTP,需要在application标签中添加android:usesCleartextTraffic="true"。ACCESS_NETWORK_STATE:可选,但推荐,用于检查网络连接状态,避免在没有网络时发起请求。
内存优化
- 图片大小:直接下载原图可能会导致内存占用过高,特别是对于大图或高分辨率屏幕,最佳实践是让服务器提供不同尺寸的图片(通过 URL 参数指定宽度/高度,如
.../image.jpg?width=300)。 - Glide 的配置:Glide 默认会进行内存缓存和磁盘缓存,大大提高了性能和减少了流量消耗,你可以根据需要配置其缓存策略。
错误处理
- 网络错误:捕获
IOException或HttpException。 - 空指针:确保在请求完成前,
ImageView或其他 UI 组件没有被销毁。 - 用户反馈:当下载失败时,向用户显示错误信息(如 Toast、Snackbar)或一个默认的占位图。
生命周期管理
- 现代库的优势:Retrofit + Coroutines + Glide 的组合天然地与 Android 的生命周期绑定,当
Activity或Fragment进入Destroy状态时,协程和 Glide 的加载任务会自动取消,不会导致内存泄漏,这是使用现代方案的最大优势之一。
| 特性 | 基础方案 (HttpURLConnection) | 现代方案 (Retrofit + Glide) |
|---|---|---|
| 依赖 | 无需第三方库 | 需要添加 Retrofit, Glide, Coroutines 库 |
| 代码量 | 较多,需要手动管理线程 | 极少,代码简洁 |
| 线程管理 | 手动使用 AsyncTask 或 Handler |
自动,由 Coroutines 和 Glide 处理 |
| 生命周期 | 容易内存泄漏,需手动处理 | 自动绑定,安全可靠 |
| 功能 | 仅能下载,无缓存等功能 | 内置缓存、转换、生命周期管理等强大功能 |
| 推荐度 | 仅用于学习原理,不用于新项目 | 强烈推荐,是当前 Android 开发的行业标准 |
对于任何新的 Android 项目,强烈建议你采用 方案二 的现代技术栈,它能让你更专注于业务逻辑,而不是处理底层的、繁琐的技术细节。
