10 网络请求基础¶
App 联网(拉取数据、提交表单)是最常见需求之一。安卓不允许在主线程做网络请求(会崩/卡死),所以必须放子线程。
10.1 添加网络权限¶
AndroidManifest.xml 里 <manifest> 下加:
<uses-permission android:name="android.permission.INTERNET" />
注意:调试 http(非 https)明文地址,Android 9+ 默认禁止明文流量。开发期可在
AndroidManifest.xml的<application>加android:usesCleartextTraffic="true";正式环境应全用 https。
10.2 依赖与选库¶
| 库 | 说明 |
|---|---|
| HttpURLConnection | JDK 自带,零依赖,学原理用 |
| OkHttp | 最流行的网络库,好用 |
| Retrofit | 在 OkHttp 之上做接口封装,大项目标配 |
| Gson / Moshi | JSON 解析 |
推荐起步 OkHttp + Gson:
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.google.code.gson:gson:2.10.1")
10.3 OkHttp GET 示例¶
OkHttpClient client = new OkHttpClient();
// 请求必须放子线程
new Thread(() -> {
try {
Request request = new Request.Builder()
.url("https://api.example.com/articles")
.build();
try (Response response = client.newCall(request).execute()) {
String body = response.body().string(); // JSON 字符串
// 回到主线程更新 UI
runOnUiThread(() -> {
tvResult.setText(body);
});
}
} catch (Exception e) {
runOnUiThread(() -> Toast.makeText(this, "请求失败:" + e.getMessage(), Toast.LENGTH_SHORT).show());
}
}).start();
10.4 POST + JSON 示例¶
new Thread(() -> {
try {
String json = "{\"username\":\"pyz\",\"password\":\"123456\"}";
RequestBody body = RequestBody.create(
json, okhttp3.MediaType.parse("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url("https://api.example.com/login")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
String resp = response.body().string();
runOnUiThread(() -> tvResult.setText(resp));
}
} catch (Exception e) {
runOnUiThread(() -> Toast.makeText(this, "请求失败", Toast.LENGTH_SHORT).show());
}
}).start();
10.5 Gson 解析 JSON¶
// JSON: [{"id":1,"title":"标题A"},{"id":2,"title":"标题B"}]
// 对应类:
// public class Item { public int id; public String title; }
Type type = new TypeToken<List<Item>>(){}.getType();
List<Item> items = new Gson().fromJson(jsonStr, type);
// items 就能直接塞进 RecyclerView 了
10.6 子线程三件套¶
| 需求 | 写法 |
|---|---|
| 开线程 | new Thread(() -> {...}).start() |
| 回主线程更新 UI | runOnUiThread(() -> {...}) |
| Activity 销毁了别乱更新 | 更新前判断 if (isFinishing() || isDestroyed()) return; |
进阶提示:更规范的做法是 Handler/Looper、协程或 RxJava,但"Thread + runOnUiThread"足够理解全部原理。
10.7 常见报错排查¶
| 报错/现象 | 原因 |
|---|---|
NetworkOnMainThreadException |
网络请求写主线程了,挪进子线程 |
CLEARTEXT communication not permitted |
用了 http 明文,正式环境换 https,或加 usesCleartextTraffic |
| 请求超时 | 网络不通/地址错/服务器没开;先在浏览器验证 URL |
| 返回 JSON 解析报错 | 用在线 JSON 查看器核对字段名是否一致 |
本章练习:找一个公开 API(如天气/GitHub),GET 回来用 Gson 解析成对象并 Toast/显示第一条数据。