Android 网络编程基础回顾

说实话,很多 Android 开发者工作两三年了,还在用 OkHttp 写网络请求,但一问起 HTTP 协议底层的东西——比如请求行、状态码、报文结构——就支支吾吾。我个人习惯是:先把地基打牢,再去谈框架怎么封装。

这节我们就快速过一下 HTTP 协议、URLConnection 和 HttpClient 的对比,以及 AsyncTask 为什么让你“又爱又恨”。这几个基础点,正是后续理解 OkHttp 与 GATT 回调泄漏混合场景的关键铺垫。


1. HTTP 协议,你真的懂了吗?

HTTP 是超文本传输协议,说白了就是客户端和服务器之间约定好的“说话格式”。我见过不少同事,明明返回 404 了还在代码里疯狂抓取 response body,就是没有先检查状态码——这就是协议基础不牢。

核心要点:请求-响应模型

  • 请求行:GET /index.html HTTP/1.1
  • 请求头:Host、User-Agent、Content-Type 等
  • 请求体:POST 时传输的数据(JSON / 表单)
  • 状态码:2xx 成功 / 3xx 重定向 / 4xx 客户端错误 / 5xx 服务器错误
  • 响应头:Content-Length、Set-Cookie、Cache-Control

💡 我的经验:有一次线上问题,用户反馈图片加载慢,我抓包发现服务端返回的 Cache-Control: no-cache 导致每次都重新下载。如果不懂这些头字段,排查方向就会跑偏。

Android 中的 HTTP 版本支持

API 级别默认支持的协议
API 23 以下HTTP/1.1 + SSL
API 23+HTTP/1.1 + HTTP/2 (需 OkHttp 或 Cronet)
API 28+HTTP/2 可通过 android:usesCleartextTraffic 配置

你想想看,HTTP/2 多路复用、头部压缩,这些特性对移动端网络优化意义重大——但前提是你得用支持它的客户端。OkHttp 从 3.0 开始就原生支持 HTTP/2,这也是它取代原生 API 的原因之一。


2. URLConnection 与 HttpClient:老将退役

Android 原生网络 API 经历了两个阶段:早期 HttpURLConnection,后来 Google 又加入了 Apache HttpClient。嗯,这两兄弟各有各的槽点。

对比一览

特性HttpURLConnectionApache HttpClient
易用性代码冗长,需要手动处理流相对简洁,不过 API 混乱
连接池默认不开启(需自己实现)内置连接池,但不够灵活
重定向自动跟随需手动配置
HTTPS支持,但配置复杂支持,但证书校验逻辑可读性差
性能较慢,无压缩稍好,但多线程下会出现死锁
Android 官方态度推荐(API 28 后仍是底层实现)Android 6.0 开始移除

⚠️ 曾经踩过的坑:我参与过一个遗留项目,还在用 Apache HttpClient 4.x 打请求。某个版本升级后,因为库冲突导致所有 POST 请求都变成 GET,排查了一整天才发现是 Android 9 移除了 httpclient 相关类。从那以后,我只用 OkHttp。

说白了,这两个原生 API 最大的问题就是:没有自动重试、没有连接池、没有拦截器机制。你写一个简单的 JSON 请求可能需要 30 行代码,还得自己关流、处理线程。

// 使用 HttpURLConnection 的典型样板代码
URL url = new URL("https://api.example.com/data");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String inputLine;
    StringBuilder response = new StringBuilder();
    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();
}
conn.disconnect();

你看,就一个 GET 请求,光 try-catch 就要写三四层。更别提文件上传、进度回调了——写法简直折磨人。


3. AsyncTask:为什么它被废弃了?

AsyncTask 是 Android 1.6 就引入的线程工具类,初衷是解决「主线程不能做网络请求」的问题。我在早期项目里用它做过图片加载、数据解析,但后来项目越做越大,AsyncTask 的毛病全暴露了。

局限性总结

  1. 内存泄漏:非静态内部类持有 Activity 引用,Activity 销毁后 AsyncTask 还在跑,导致内存泄漏。
  2. 串行执行:默认单线程池(AsyncTask 在 Android 11 前是串行),多个任务会排队,无法并发。
  3. 生命周期不可控:AsyncTask 没有和 Activity/Fragment 生命周期联动,屏幕旋转时 Activity 重建,AsyncTask 的 callback 会更新旧的 View,导致崩溃。
  4. 缺乏错误处理:doInBackground 里抛异常直接 crash,除非自己 catch 并传参。
  5. 调试困难:嵌套 AsyncTask 时,执行顺序和线程切换完全靠猜。

💣 血泪教训:我曾经在一个大列表页面里,每项都启动一个 AsyncTask 去加载头像。结果屏幕旋转后,几十个 AsyncTask 同时回调更新已销毁的 ImageView,直接 ANR。这种问题用 AsyncTask 几乎无解,后来改用 RxJava + 生命周期绑定才彻底解决。

所以 Android 官方在 API 30 正式标记 AsyncTask 为废弃,并推荐使用 Kotlin 协程 或 线程池 + Handler。你可能会问:"那我不学 AsyncTask 行不行?"——我的建议是:至少要知道它为什么不行,这样你才能理解 OkHttp 的异步回调设计有多巧妙。


知识框架图:从原生到 OkHttp 的演进

下面这张图展示了 Android 网络编程的基础组件关系,以及 AsyncTask 被抛弃的原因——它本来就不是为网络请求而生的。

Android 网络编程基础回顾 - 知识体系 HTTP 协议 请求-响应 + 状态码 + 头部 HttpURLConnection 代码冗长 / 无连接池 Apache HttpClient 已废弃 / 内存泄漏 AsyncTask(已被废弃) 内存泄漏 + 串行执行 + 生命周期不可控 OkHttp(现代替代方案) 连接池 · 拦截器 · 自动重试 · HTTP/2 支持 核心结论 ① HTTP 协议是底层基础,必须掌握状态码和报文结构 ② URLConnection / HttpClient 已被历史淘汰,不要在新项目中使用 ③ AsyncTask 的局限性非常致命,推荐使用协程或线程池+Callback

小结一下

这一节我们回顾了 HTTP 协议的核心要素,对比了两个原生网络 API 的优劣,也剖析了 AsyncTask 被废弃的真正原因。说白了,这些东西都是你在面试、写代码、排查问题时的基本功。下一节我们会真正进入 OkHttp 的世界——但如果你连「为什么不用 URLConnection」都说不清,那后面的优化技巧你也很难理解到位。

💡 新手特别提示:不要试图用 AsyncTask 封装网络请求!即使你只是写一个小 Demo,也请直接从 OkHttp 或者 Retrofit 开始。养成好习惯,以后重构成本低很多。