核心流程
无论使用哪种方法,下载图片的基本流程都是相同的:

- 发起网络请求:向服务器的图片 URL 发送一个 HTTP/HTTPS 请求。
- 获取输入流:从服务器的响应中获取图片数据的输入流。
- 解码图片:使用 Android 的
BitmapFactory将输入流解码成Bitmap对象。 - 处理结果:
- UI 线程:将
Bitmap显示在ImageView上。 - 后台线程:将
Bitmap保存到设备存储(如相册或应用私有目录)。
- UI 线程:将
- 处理异常:处理网络错误、IO 错误、解码失败等各种异常情况。
使用 HttpURLConnection (传统方式)
这是 Java 标准库自带的网络 API,不依赖第三方库,适合简单的下载任务。
步骤:
-
添加网络权限:在
AndroidManifest.xml中声明。<uses-permission android:name="android.permission.INTERNET" /> <!-- 如果需要写入外部存储(如保存到相册) --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />注意:从 Android 10 (API 29) 开始,写入外部存储需要
MANAGE_EXTERNAL_STORAGE权限,但更推荐使用MediaStoreAPI 来保存图片到相册。 -
编写下载代码: 强烈建议在后台线程(如
AsyncTask、Thread或ExecutorService)中执行网络请求,以避免阻塞 UI 线程导致应用无响应。
(图片来源网络,侵删)下面是一个使用
ExecutorService的例子:import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MainActivity extends AppCompatActivity { private static final String IMAGE_URL = "https://example.com/your_image.jpg"; private ImageView imageView; private ExecutorService executorService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); // 创建一个单线程的执行器 executorService = Executors.newSingleThreadExecutor(); // 启动下载任务 executorService.execute(new DownloadImageTask()); } private class DownloadImageTask implements Runnable { @Override public void run() { Bitmap bitmap = null; HttpURLConnection connection = null; InputStream inputStream = null; try { URL url = new URL(IMAGE_URL); connection = (HttpURLConnection) url.openConnection(); connection.connect(); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { inputStream = connection.getInputStream(); // 从输入流解码Bitmap bitmap = BitmapFactory.decodeStream(inputStream); } else { Log.e("DownloadImage", "HTTP Error Code: " + responseCode); } } catch (IOException e) { Log.e("DownloadImage", "Error downloading image", e); } finally { // 确保流和连接被关闭 if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (connection != null) { connection.disconnect(); } } // 在UI线程更新UI final Bitmap finalBitmap = bitmap; runOnUiThread(new Runnable() { @Override public void run() { if (finalBitmap != null) { imageView.setImageBitmap(finalBitmap); } else { // 可以设置一个默认图片或显示错误信息 imageView.setImageResource(R.drawable.ic_error); } } }); } } @Override protected void onDestroy() { super.onDestroy(); // 关闭执行器,防止内存泄漏 if (executorService != null && !executorService.isShutdown()) { executorService.shutdown(); } } }
使用 OkHttp (强烈推荐)
OkHttp 是目前 Android 开发中最流行的网络库,它更高效、更易用,并内置了对现代网络协议的支持(如 HTTP/2)。
步骤:
-
添加依赖:在
app/build.gradle文件中添加OkHttp依赖。dependencies { implementation("com.squareup.okhttp3:okhttp:4.12.0") // 使用最新版本 } -
编写下载代码:
OkHttp的回调在后台线程执行,所以同样需要切换到 UI 线程来更新界面。
(图片来源网络,侵删)import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; import java.io.InputStream; public class MainActivity extends AppCompatActivity { private static final String IMAGE_URL = "https://example.com/your_image.jpg"; private ImageView imageView; private OkHttpClient okHttpClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); okHttpClient = new OkHttpClient(); downloadImageWithOkHttp(); } private void downloadImageWithOkHttp() { Request request = new Request.Builder() .url(IMAGE_URL) .build(); okHttpClient.newCall(request).enqueue(new okhttp3.Callback() { @Override public void onFailure(okhttp3.Call call, IOException e) { // 在后台线程执行,处理失败 Log.e("OkHttp", "Download failed", e); runOnUiThread(() -> { imageView.setImageResource(R.drawable.ic_error); }); } @Override public void onResponse(okhttp3.Call call, Response response) throws IOException { // 在后台线程执行,处理成功 if (response.isSuccessful()) { InputStream inputStream = response.body().byteStream(); final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // 切换到UI线程更新ImageView runOnUiThread(() -> { if (bitmap != null) { imageView.setImageBitmap(bitmap); } else { imageView.setImageResource(R.drawable.ic_error); } }); } else { Log.e("OkHttp", "Response not successful: " + response.code()); runOnUiThread(() -> { imageView.setImageResource(R.drawable.ic_error); }); } } }); } @Override protected void onDestroy() { super.onDestroy(); // 可以在这里关闭OkHttpClient,但通常它作为单例使用 // okHttpClient.dispatcher().executorService().shutdown(); } }
使用 Glide 或 Picasso (最佳实践 - 专为图片设计)
对于加载和显示图片,直接使用 Glide 或 Picasso 是最简单、最高效的方式,它们不仅处理了下载,还管理了内存缓存、磁盘缓存、图片缩放、线程池等所有复杂细节。
使用 Glide (推荐)
Glide 是 Google 推荐的图片加载库,性能优异,功能强大。
-
添加依赖:
dependencies { implementation("com.github.bumptech.glide:glide:4.16.0") // 使用最新版本 annotationProcessor("com.github.bumptech.glide:compiler:4.16.0") } -
编写代码: 代码极其简洁!只需一行。
import android.os.Bundle; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; import com.bumptech.glide.Glide; public class MainActivity extends AppCompatActivity { private static final String IMAGE_URL = "https://example.com/your_image.jpg"; private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); // 一行代码搞定!Glide会自动处理后台下载、缓存和UI更新。 Glide.with(this) .load(IMAGE_URL) .into(imageView); } }
使用 Picasso
Picasso 由 Square 公司开发,曾经非常流行,但现在维护较少,新项目更推荐 Glide。
-
添加依赖:
dependencies { implementation("com.squareup.picasso:picasso:2.8") // 使用最新版本 } -
编写代码: 同样非常简单。
import android.os.Bundle; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; import com.squareup.picasso.Picasso; public class MainActivity extends AppCompatActivity { private static final String IMAGE_URL = "https://example.com/your_image.jpg"; private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); // 一行代码搞定 Picasso.get().load(IMAGE_URL).into(imageView); } }
总结与对比
| 特性 | HttpURLConnection |
OkHttp |
Glide / Picasso |
|---|---|---|---|
| 易用性 | 较低,需要手动处理线程和流 | 中等,回调简洁 | 极高,一行代码 |
| 功能 | 基础的 HTTP 请求 | 强大,支持 HTTP/2,Interceptor 等 | 专业,自动缓存、缩放、转换、占位图 |
| 性能 | 一般 | 优秀 | 优秀,针对图片优化 |
| 依赖 | 无(Android SDK 内置) | 需添加第三方库 | 需添加第三方库 |
| 适用场景 | 简单、无依赖的 Demo 或学习 | 所有需要网络请求的 App(不仅仅是图片) | 任何需要显示网络图片的 App |
最终建议
- 如果你只是想快速学习网络请求的原理:使用
HttpURLConnection。 - 如果你正在开发一个需要网络通信的现代 App:使用
OkHttp,它是网络请求的事实标准。 - 如果你的 App 需要加载和显示图片:直接使用
Glide,这是最佳实践,能让你从繁琐的图片处理细节中解放出来,专注于业务逻辑,它内部其实也使用了OkHttp作为默认的HttpClient。
