Android 网络编程全面教程
本教程将带你从零开始,学习如何在 Android 应用中进行网络请求,并最终掌握业界标准的现代网络解决方案。

目录
-
第一部分:基础准备
- 1 网络权限
- 2 主线程与子线程(UI 线程)
- 3 添加网络依赖库
-
第二部分:经典方式 - HttpURLConnection
- 1 基本使用(GET 请求)
- 2 POST 请求与参数传递
- 3 优缺点分析
-
第三部分:现代方式 - Retrofit + OkHttp
- 1 为什么选择 Retrofit?(优点)
- 2 搭建 Retrofit 环境
- 3 定义 API 接口
- 4 发起同步和异步请求
- 5 处理响应数据(JSON 解析)
- 6 完整示例:获取并显示 GitHub 用户列表
-
第四部分:进阶主题
(图片来源网络,侵删)- 1 图片加载库:Glide / Picasso
- 2 数据持久化:Room + Retrofit(MVVM 架构)
- 3 网络状态监听
-
第五部分:最佳实践与总结
第一部分:基础准备
在学习网络请求之前,必须了解几个基本概念。
1 网络权限
你的应用需要明确告知系统它需要访问互联网,在 注意:从 Android 9 (API 28) 开始,默认情况下,应用只能使用 HTTPS,如果你的 API 服务器只有 HTTP,需要在 Android 的 UI 操作(如更新 TextView、显示 Toast)必须在主线程(UI 线程)中执行,而网络请求是一个耗时操作,如果在主线程中进行,会导致应用无响应,甚至出现ANR (Application Not Responding) 错误。 解决方案:所有网络请求都必须在子线程(后台线程)中执行。 现代 Android 开发强烈推荐使用第三方库来简化网络操作,我们将使用以下组合: 在 这是 Android SDK 自带的网络 API,无需额外依赖,了解它有助于理解网络请求的本质。 POST 请求需要将参数放在请求体中。 无需额外依赖,是 Android SDK 的一部分。 在现代开发中,除非有特殊限制,否则不推荐直接使用 这是目前 Android 网络编程的事实标准,它极大地简化了网络请求的代码。 请参考第一部分 这是 Retrofit 的核心,创建一个接口,用注解来描述 API 的信息。 创建 Retrofit 实例: 异步请求(推荐): 同步请求: Retrofit + Gson 可以自动将 JSON 响应体转换成我们定义的 Kotlin 数据类。 定义数据类: Retrofit 自动转换: 当你调用 转换成 布局文件 数据类 (需要创建 网络图片加载是一个复杂的问题(缓存、缩放、生命周期管理等),强烈推荐使用成熟的库。 Glide 使用示例: 一个好的应用不会每次都从网络获取数据,通常的流程是: 这构成了一个典型的 MVVM (Model-View-ViewModel) 架构, 可以使用 希望这份教程能帮助你顺利掌握 Android 网络编程!祝你编码愉快!AndroidManifest.xml 文件中添加 <uses-permission>
<!-- 在 <manifest> 标签内部添加 -->
<uses-permission android:name="android.permission.INTERNET" />
application 标签下添加 android:usesCleartextTraffic="true"。<application
...
android:usesCleartextTraffic="true">
...
</application>
2 主线程与子线程(UI 线程)

3 添加网络依赖库
app/build.gradle.kts (或 app/build.gradle) 文件中添加依赖:// build.gradle.kts (Kotlin DSL)
dependencies {
// Retrofit: 核心库
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Gson: JSON 转换器
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// OkHttp: 日志拦截器,方便调试
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
// Glide: 图片加载库
implementation("com.github.bumptech.glide:glide:4.16.0")
kapt "com.github.bumptech.glide:compiler:4.16.0" // 如果使用 Kotlin,需要添加 kapt
}
第二部分:经典方式 - HttpURLConnection
1 基本使用(GET 请求)
// 在子线程中执行
thread {
val url = URL("https://api.github.com/users/octocat")
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
try {
val responseCode = connection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val inputStream = connection.inputStream
val response = inputStream.bufferedReader().use { it.readText() }
// response 就是服务器返回的 JSON 字符串
Log.d("HttpURLConnection", response)
} else {
Log.e("HttpURLConnection", "GET request failed with code: $responseCode")
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
connection.disconnect()
}
}
2 POST 请求与参数传递
thread {
val url = URL("https://example.com/api/login")
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
connection.doOutput = true // 允许输出
val postData = "username=test&password=123456"
val outputStream = connection.outputStream
outputStream.write(postData.toByteArray())
outputStream.flush()
// ... 后续处理响应代码和输入流,与 GET 类似 ...
outputStream.close()
}
3 优缺点分析
HttpURLConnection。
第三部分:现代方式 - Retrofit + OkHttp
1 为什么选择 Retrofit?
HttpURLConnection 的样板代码。2 搭建 Retrofit 环境
3 添加 Retrofit, OkHttp, Gson 的依赖。3 定义 API 接口
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
interface GitHubApiService {
// GET 请求,路径是 "users/{user}"
// {user} 是一个路径参数
@GET("users/{user}")
fun getUser(@Path("user") username: String): Call<User>
// GET 请求,路径是 "users"
@GET("users")
fun getUsers(): Call<List<User>>
}
4 发起同步和异步请求
object RetrofitClient {
private const val BASE_URL = "https://api.github.com/"
val instance: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) // 添加 Gson 转换器
.build()
}
}
val apiService = RetrofitClient.instance.create(GitHubApiService::class.java)
// 发起异步 GET 请求
apiService.getUser("google").enqueue(object : Callback<User> {
override fun onResponse(call: Call<User>, response: Response<User>) {
if (response.isSuccessful) {
// 请求成功
val user = response.body()
Log.d("Retrofit", "User: ${user?.login}, Name: ${user?.name}")
// 在主线程更新 UI
runOnUiThread {
// tvUserName.text = user?.name
}
} else {
// 服务器返回错误,如 404, 500 等
Log.e("Retrofit", "Error: ${response.code()}")
}
}
override fun onFailure(call: Call<User>, t: Throwable) {
// 网络连接失败或解析失败
Log.e("Retrofit", "Failure: ${t.message}")
}
})
// 注意:同步请求必须在子线程中调用,否则会阻塞主线程
thread {
try {
val response = apiService.getUser("jetbrains").execute()
if (response.isSuccessful) {
val user = response.body()
Log.d("Retrofit", "Sync User: ${user?.login}")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
5 处理响应数据(JSON 解析)
// data class 对应 JSON 的结构
data class User(
val login: String,
val id: Int,
val avatar_url: String,
val name: String?,
val public_repos: Int
)
response.body() 时,Gson 会自动将类似以下的 JSON 字符串:{
"login": "google",
"id": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/1?v=4",
"name": "Google",
"public_repos": 50
}
User 对象。6 完整示例:获取并显示 GitHub 用户列表
activity_main.xml:<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvUsers"
android:layout_width="match_parent"
android:layout_height="match_parent" />
User.kt:data class User(val login: String, val avatar_url: String)
UserAdapter.kt (RecyclerView 适配器):class UserAdapter(private val users: List<User>) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val ivAvatar: ImageView = itemView.findViewById(R.id.ivAvatar)
val tvLogin: TextView = itemView.findViewById(R.id.tvLogin)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
return UserViewHolder(view)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = users[position]
holder.tvLogin.text = user.login
// 使用 Glide 加载图片
Glide.with(holder.itemView.context)
.load(user.avatar_url)
.into(holder.ivAvatar)
}
override fun getItemCount() = users.size
}
item_user.xml 布局,包含一个 ImageView 和一个 TextView)MainActivity.kt:class MainActivity : AppCompatActivity() {
private lateinit var apiService: GitHubApiService
private lateinit var adapter: UserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rvUsers = findViewById<RecyclerView>(R.id.rvUsers)
rvUsers.layoutManager = LinearLayoutManager(this)
adapter = UserAdapter(emptyList())
rvUsers.adapter = adapter
// 初始化 Retrofit
apiService = RetrofitClient.instance.create(GitHubApiService::class.java)
// 发起请求
fetchUsers()
}
private fun fetchUsers() {
apiService.getUsers().enqueue(object : Callback<List<User>> {
override fun onResponse(call: Call<List<User>>, response: Response<List<User>>) {
if (response.isSuccessful) {
response.body()?.let { users ->
// 更新 UI
adapter.updateUsers(users) // 假设你给 adapter 添加了 updateUsers 方法
}
}
}
override fun onFailure(call: Call<List<User>>, t: Throwable) {
Log.e("MainActivity", "Failed to fetch users: ${t.message}")
}
})
}
}
第四部分:进阶主题
1 图片加载库:Glide / Picasso
// 在 Activity/Fragment 中加载图片
Glide.with(this) // 上下文
.load("https://example.com/image.jpg") // 图片 URL
.into(imageView) // 目标 ImageView
2 数据持久化:Room + Retrofit(MVVM 架构)
3 网络状态监听
ConnectivityManager 和 NetworkCapabilities 来监听网络状态的变化(如从 Wi-Fi 切换到移动数据)。val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
val hasInternet = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
第五部分:最佳实践与总结
thread, AsyncTask (已废弃), ExecutorService, 或者协程 (Coroutines)。response.isSuccessful,并妥善处理 onFailure 回调中的网络异常和服务器错误。
