13、网络请求基础:HttpURLConnection与OkHttp的使用,GET/POST请求,JSON数据解析(Gson/FastJson)
网络请求,说白了就是你的App跟服务器“打电话”。我刚开始做Android开发那会儿,网络这块真是踩了不少坑。今天咱们就把HttpURLConnection和OkHttp这两个最常用的网络库讲透,顺便把JSON解析也一并拿下。
13.1 网络请求的核心流程
不管用哪个库,网络请求的套路其实都差不多。我习惯把它分成三步:
- 建立连接——告诉服务器我要找谁
- 发送数据——把请求发出去(GET或POST)
- 解析响应——把服务器返回的数据变成我们能用的对象
你想想看,这跟你去餐厅点餐是一个道理:先找到服务员(建立连接),然后点菜(发送请求),最后菜端上来你吃掉(解析数据)。
13.2 HttpURLConnection——Android自带的“老伙计”
HttpURLConnection是JDK自带的网络类,Android里也能直接用。说实话,它用起来有点啰嗦,但胜在不需要引入任何第三方库。我在早期维护一个老项目时,用的就是它。
13.2.1 GET请求示例
// 创建一个URL对象
URL url = new URL("https://api.example.com/users?page=1");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方式
connection.setRequestMethod("GET");
// 设置超时时间(单位:毫秒)
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
// 设置请求头(模拟浏览器)
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
connection.setRequestProperty("Accept", "application/json");
// 获取响应码
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 读取响应数据
BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
System.out.println("响应数据:" + response.toString());
} else {
System.out.println("请求失败,响应码:" + responseCode);
}
// 记得关闭连接
connection.disconnect();
disconnect()。我曾经因为忘记关闭连接,导致线上App出现内存泄漏,排查了好久才发现是连接没释放。
13.2.2 POST请求示例
URL url = new URL("https://api.example.com/users");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
// POST请求必须开启输出流
connection.setDoOutput(true);
connection.setDoInput(true);
// 设置请求头
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// 构建请求体(JSON格式)
String jsonBody = "{\"name\":\"张三\",\"age\":25}";
// 写入请求体
OutputStream os = connection.getOutputStream();
os.write(jsonBody.getBytes("UTF-8"));
os.flush();
os.close();
int responseCode = connection.getResponseCode();
// ... 读取响应的代码跟GET一样,这里省略
connection.disconnect();
setDoOutput(true),结果服务器一直收不到数据。这个属性默认是false,必须手动开启。另外,Content-Type一定要写对,不然服务器解析不了你的JSON。
13.3 OkHttp——更优雅的网络请求方案
说实话,现在大部分项目都在用OkHttp。它比HttpURLConnection好用太多了,链式调用、连接池复用、自动重试……这些特性让开发效率提升不少。
要使用OkHttp,先在build.gradle里加依赖:
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
13.3.1 GET请求示例
// 创建OkHttpClient实例(建议全局单例)
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
// 构建请求
Request request = new Request.Builder()
.url("https://api.example.com/users?page=1")
.addHeader("User-Agent", "Mozilla/5.0")
.addHeader("Accept", "application/json")
.get()
.build();
// 同步执行(需要在子线程)
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("响应数据:" + responseBody);
} else {
System.out.println("请求失败:" + response.code());
}
} catch (IOException e) {
e.printStackTrace();
}
13.3.2 POST请求示例
// 构建JSON请求体
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String jsonBody = "{\"name\":\"李四\",\"age\":30}";
RequestBody body = RequestBody.create(jsonBody, JSON);
// 构建请求
Request request = new Request.Builder()
.url("https://api.example.com/users")
.post(body)
.addHeader("Accept", "application/json")
.build();
// 执行请求
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("响应数据:" + responseBody);
}
} catch (IOException e) {
e.printStackTrace();
}
response.body().string()只能调用一次!我第一次用的时候没注意,调了两次,第二次返回空字符串。原因是OkHttp的响应体是流式的,读完就没了。如果需要多次使用,先存到变量里。
13.4 JSON数据解析——Gson vs FastJson
服务器返回的数据通常是JSON格式,我们需要把它转成Java对象。目前最主流的两个库是Gson(Google出品)和FastJson(阿里巴巴出品)。
先加依赖:
// Gson
implementation 'com.google.code.gson:gson:2.10.1'
// FastJson
implementation 'com.alibaba:fastjson:2.0.40'
13.4.1 定义数据模型
假设服务器返回的JSON长这样:
{
"code": 200,
"message": "成功",
"data": {
"id": 1001,
"name": "王五",
"age": 28,
"email": "wangwu@example.com"
}
}
对应的Java类:
// 外层响应类
public class ApiResponse<T> {
private int code;
private String message;
private T data;
// getter/setter 省略
}
// 用户信息类
public class User {
private int id;
private String name;
private int age;
private String email;
// getter/setter 省略
}
13.4.2 使用Gson解析
// 拿到服务器返回的JSON字符串
String jsonString = "{\"code\":200,\"message\":\"成功\",\"data\":{\"id\":1001,\"name\":\"王五\",\"age\":28,\"email\":\"wangwu@example.com\"}}";
// 创建Gson实例
Gson gson = new Gson();
// 解析为ApiResponse对象
// 注意:这里要用TypeToken来获取泛型类型
Type type = new TypeToken<ApiResponse<User>>() {}.getType();
ApiResponse<User> response = gson.fromJson(jsonString, type);
// 获取数据
if (response.getCode() == 200) {
User user = response.getData();
System.out.println("用户名:" + user.getName());
System.out.println("邮箱:" + user.getEmail());
}
13.4.3 使用FastJson解析
// FastJson解析,代码更简洁
String jsonString = "{\"code\":200,\"message\":\"成功\",\"data\":{\"id\":1001,\"name\":\"王五\",\"age\":28,\"email\":\"wangwu@example.com\"}}";
// 直接解析,不需要TypeToken
ApiResponse<User> response = JSON.parseObject(jsonString,
new TypeReference<ApiResponse<User>>() {});
if (response.getCode() == 200) {
User user = response.getData();
System.out.println("用户名:" + user.getName());
}
13.5 实战:完整的网络请求+解析流程
咱们把上面学的串起来,写一个完整的例子:
public class NetworkHelper {
private static OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
private static Gson gson = new Gson();
/**
* 发送GET请求并解析为指定类型
*/
public static <T> ApiResponse<T> doGet(String url, Type type) {
Request request = new Request.Builder()
.url(url)
.get()
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String jsonString = response.body().string();
return gson.fromJson(jsonString, type);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 发送POST请求并解析为指定类型
*/
public static <T> ApiResponse<T> doPost(String url, Object requestBody, Type type) {
String jsonBody = gson.toJson(requestBody);
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(jsonBody, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String jsonString = response.body().string();
return gson.fromJson(jsonString, type);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
13.6 本章小结
网络请求这块,说白了就是三板斧:建连接、发请求、解析数据。HttpURLConnection是基本功,OkHttp是进阶利器。我个人建议新项目直接用OkHttp,省心省力。JSON解析方面,Gson和FastJson二选一就行,不用纠结。
嗯,这里要注意一点:网络请求的代码一定要做好封装,不要到处new OkHttpClient。我见过一个项目里每个Activity都自己创建HttpURLConnection,代码冗余不说,连接也没复用,性能很差。封装成一个工具类,全局维护一个OkHttpClient实例,这才是正确的姿势。
公众号:蓝海资料掘金营,微信deep3321