网络基础
本教程共 100 篇 · 第 69 篇 · 更新于 2026-07-28 · 约 7 分钟阅读
69. 网络基础
本节目标:了解 Android 应用访问网络的规矩,包括权限声明、主线程限制、明文 HTTP 策略、HTTPS 配置,认识主流网络栈 Retrofit + OkHttp,为后面写接口请求打基础。
几乎所有应用都要联网:拉新闻列表、登录账号、上传图片。Android 在网络这块管得比较严,规矩没搞清楚就一堆坑。这章先把规矩说透,下一章再上 Retrofit。
先说权限
应用要联网,第一件事是在 AndroidManifest.xml 里声明权限:
<uses-permission android:name="android.permission.INTERNET" />
这是普通权限,不用运行时请求,安装时就生效。忘了加这行,请求会直接抛 SecurityException,新手十有八九踩过。
NoteAndroid 9(API 28)起默认禁止明文 HTTP 后,调试时可以在 manifest 里加
android:usesCleartextTraffic="true"临时允许明文 HTTP,正式版本仍然要走 HTTPS。更推荐用network_security_config针对特定域名开放。
主线程不能发网络请求
Android 不允许在主线程(UI 线程)做网络操作。一旦在主线程调用网络 API,直接抛 NetworkOnMainThreadException。
为什么?网络是 IO 操作,慢且不可控。主线程卡 5 秒用户就觉得应用死了,系统会直接 ANR(应用无响应)弹窗。
打个比方,主线程像餐厅服务员,要不停招呼客人。你让他去后院等外卖送来,这一等就是 30 秒,前面排队的客人全怒了。所以服务员只能把这事丢给后厨(子线程),自己继续服务。
所以网络请求必须在子线程,或者用协程的 Dispatchers.IO:
// 错误:主线程发请求会崩
fun fetchWrong() {
val result = URL("https://api.example.com/data").readText()
}
// 正确:协程切到 IO 线程
suspend fun fetchOk(): String = withContext(Dispatchers.IO) {
URL("https://api.example.com/data").readText()
}
Tip用 Retrofit + 协程的话,方法标
suspend,Retrofit 自动切线程,不用自己withContext。
明文 HTTP 默认禁用
从 Android 9(API 28)起,默认禁止明文 HTTP 流量,所有请求必须走 HTTPS。这是为了防止中间人攻击窃听数据。
如果非要连一个 http:// 的接口(比如本地调试服务器),要在 res/xml/ 下建 network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
</network-security-config>
然后 manifest 里引用:
<application
android:networkSecurityConfig="@xml/network_security_config"
... >
Warning只针对调试域名开放明文,别图省事写
<base-config cleartextTrafficPermitted="true">,那样整个应用都允许明文,正式版会被 Google Play 拒审。
HTTPS 与证书
HTTPS 在 HTTP 下加了 TLS 加密,正常情况下系统自带信任库能验证大部分公网证书,不用额外配置。
只有几种情况要特殊处理:
- 自签证书(开发服务器常见):要么把证书加进应用,要么用
network_security_config信任。 - 证书固定(Certificate Pinning):防止证书被替换,OkHttp 直接支持。
- 用户证书:默认不信任用户安装的 CA,要显式声明。
绝大多数项目用公网证书,啥都不用配,发请求就行。
主流网络栈
Android 联网方案好几套,我列一下选型:
| 方案 | 定位 | 现在用不用 |
|---|---|---|
HttpURLConnection | 系统内置 | 能用,但写起来啰嗦,新项目基本不直接用 |
HttpClient | Apache 老库 | API 23 起已从 SDK 移除,别提了 |
| Volley | Google 出的异步网络库 | 老项目还在用,新项目少 |
| OkHttp | Square 出的 HTTP 客户端 | 主流底层库,Retrofit 内部就用它 |
| Retrofit | Square 出的 REST 客户端 | 当前主流,本教程主线 |
| Ktor | 纯 Kotlin 网络库 | 在用,但生态不如 Retrofit |
我们的主线是 Retrofit + OkHttp + 协程,理由:
- 类型安全:接口方法返回 Kotlin 对象,不用手动解析 JSON。
- 编译期校验:URL、参数写错编译报错。
- 协程友好:
suspend方法天然支持。 - 拦截器、日志、缓存都有现成方案。
NoteHttpClient 已经从 Android SDK 移除,本教程不再涉及。老代码迁移到 Retrofit 是标准做法。
用 OkHttp 发个最简单的请求
先看 OkHttp 裸用怎么发请求,理解底层机制:
val client = OkHttpClient()
val request = Request.Builder()
.url("https://jsonplaceholder.typicode.com/posts/1")
.build()
// 同步(必须子线程)
client.newCall(request).execute().use { response ->
val body = response.body?.string()
println(body)
}
// 异步(自带线程池)
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
println(response.body?.string())
}
})
OkHttp 已经够好用,但每次还要手动解析 JSON 字符串、构造 Request、处理 Callback,代码一多就乱。Retrofit 就是在 OkHttp 上加了一层「接口化」的壳,让你写接口方法代替手动拼请求,下一章详讲。
网络状态判断
应用联网前最好先判断有没有网,没网就别发请求了,省电省流量。
val cm = context.getSystemService(ConnectivityManager::class.java)
val network = cm.activeNetwork
val caps = cm.getNetworkCapabilities(network)
val hasInternet = caps?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
TipAndroid 10 以后
cm.getActiveNetworkInfo()已废弃,要用NetworkCapabilitiesAPI。如果要监听网络变化,注册NetworkCallback。
一些常见坑
我踩过几个,提前给你避雷:
- 忘加 INTERNET 权限:日志里
SecurityException,加上权限就好。 - 主线程发请求:
NetworkOnMainThreadException,老老实实切线程。 - 本地调试连不上:模拟器访问本机服务器要用
10.0.2.2而不是localhost,因为模拟器自己是个独立网络。 - 明文 HTTP 不通:默认禁明文,要么走 HTTPS,要么配
network_security_config。 - HTTP 200 不等于成功:要检查
response.isSuccessful(200-299),有些接口业务错误也返回 200,body 里塞了错误码。
小结
Android 网络开发有三条规矩要记牢:声明 INTERNET 权限、不在主线程发请求、HTTPS 优先。底层用 OkHttp,工程化用 Retrofit,配合协程基本是当下 Kotlin 项目的标配。下一章我们就把 Retrofit 跑起来。