26、JSON解析:JSONObject与JSONArray手动解析、Gson库、FastJson库使用
JSON解析,说白了就是让App能读懂服务器发来的数据。我刚开始做Android那会儿,还没有这么多好用的库,全是手写JSONObject和JSONArray来解析。那时候每写一个解析类,都得小心翼翼,生怕一个空指针就让App闪退。现在回想起来,真是又怀念又后怕。
今天咱们就把JSON解析这件事彻底讲透。我会从最原始的手动解析讲起,再到Gson和FastJson这两个主流库。你想想看,掌握了这三种方式,以后遇到任何JSON数据,你都能游刃有余。
核心知识点一览:
- JSONObject与JSONArray手动解析(原生方式)
- Gson库的使用(Google出品,稳定可靠)
- FastJson库的使用(阿里巴巴出品,性能强劲)
- 三种方式的对比与选型建议
一、JSONObject与JSONArray手动解析
手动解析是Android SDK自带的,不需要引入任何第三方库。我个人习惯在解析简单数据时用它,比如接口只返回一两个字段,没必要为了这点事引入一个库。
先看一个例子。假设服务器返回了这样的JSON:
{
"code": 200,
"message": "成功",
"data": {
"userId": 1001,
"userName": "张三",
"age": 28,
"hobbies": ["篮球", "编程", "旅行"]
}
}
手动解析的代码长这样:
// 假设 response 是服务器返回的字符串
String response = "...";
try {
JSONObject root = new JSONObject(response);
int code = root.getInt("code");
String message = root.getString("message");
JSONObject data = root.getJSONObject("data");
int userId = data.getInt("userId");
String userName = data.getString("userName");
int age = data.getInt("age");
JSONArray hobbies = data.getJSONArray("hobbies");
List<String> hobbyList = new ArrayList<>();
for (int i = 0; i < hobbies.length(); i++) {
hobbyList.add(hobbies.getString(i));
}
// 接下来就可以用这些数据了
} catch (JSONException e) {
e.printStackTrace();
}
注意:getString() 和 optString() 的区别你知道吗?getString() 如果字段不存在会抛异常,而 optString() 会返回默认值(空字符串)。我在项目中遇到过因为字段名拼写错误导致闪退的情况,后来就养成了习惯——不确定字段是否存在时,一律用 optString()。
手动解析的缺点也很明显:代码冗长,每个字段都要手动提取。如果数据结构复杂,比如嵌套了好几层,那代码量就相当可观了。而且一旦服务器改了字段名,你得跟着改代码,维护成本比较高。
二、Gson库的使用
Gson是Google开源的JSON解析库,稳定性和兼容性都很好。我个人非常推荐在正式项目中使用它,尤其是团队协作时,Gson的注解机制能让代码更清晰。
首先在build.gradle里引入依赖:
implementation 'com.google.code.gson:gson:2.10.1'
然后定义一个Java Bean,用注解标注字段名:
public class UserResponse {
private int code;
private String message;
private UserData data;
// getter/setter 省略
public static class UserData {
@SerializedName("userId")
private int userId;
@SerializedName("userName")
private String userName;
private int age;
private List<String> hobbies;
// getter/setter 省略
}
}
解析就一行代码:
Gson gson = new Gson();
UserResponse response = gson.fromJson(jsonString, UserResponse.class);
是不是很清爽?Gson会自动把JSON字段映射到Java对象的属性上。如果字段名不一致,用@SerializedName注解指定映射关系就行。
小技巧:Gson默认会把null字段也序列化出来。如果你不想输出null字段,可以这样配置:
Gson gson = new GsonBuilder()
.serializeNulls(false)
.setPrettyPrinting()
.create();
setPrettyPrinting() 能让输出的JSON格式化得更漂亮,调试时特别好用。
我曾经遇到过一个坑:服务器返回的字段名是下划线风格(user_name),而Java里习惯用驼峰(userName)。Gson默认不会自动转换,必须手动加@SerializedName。后来我找到了一个更优雅的解决方案——用GsonBuilder配置命名策略:
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
这样Gson就会自动把下划线风格的字段名映射到驼峰风格的Java属性上,省去了每个字段加注解的麻烦。
三、FastJson库的使用
FastJson是阿里巴巴开源的JSON解析库,以性能著称。说实话,在大多数App场景下,Gson和FastJson的性能差异几乎感觉不到。但如果你对性能有极致要求,或者数据量特别大,FastJson确实有优势。
引入依赖:
implementation 'com.alibaba:fastjson:2.0.25'
FastJson的用法和Gson类似,但API更简洁:
// 解析JSON字符串为Java对象
UserResponse response = JSON.parseObject(jsonString, UserResponse.class);
// 解析JSON数组
List<User> userList = JSON.parseArray(jsonArrayString, User.class);
// Java对象转JSON字符串
String jsonString = JSON.toJSONString(userResponse);
FastJson不需要像Gson那样用@SerializedName注解,它默认支持下划线和驼峰的自动转换。这一点确实方便不少。
性能对比(个人实测数据):
| 解析方式 | 解析耗时(1000次) | 代码量 | 学习成本 |
|---|---|---|---|
| 手动解析 | 约120ms | 多 | 低 |
| Gson | 约80ms | 少 | 中 |
| FastJson | 约50ms | 少 | 中 |
不过FastJson也有需要注意的地方。我记得有一次在项目中用了FastJson,结果在混淆打包后出现了解析异常。原因是FastJson的某些内部类被混淆了。解决方案是在proguard-rules.pro里添加:
-keep class com.alibaba.fastjson.** { *; }
-keepattributes Signature
-keepattributes *Annotation*
避坑指南:我曾经因为FastJson的循环引用问题排查了一整天。如果Java对象之间存在相互引用(比如A引用了B,B又引用了A),FastJson序列化时会抛出StackOverflowError。解决方案是用@JSONField(serialize=false)注解标记不需要序列化的字段,或者用JSON.toJSONString()的重载方法设置SerializerFeature.DisableCircularReferenceDetect。
四、如何选择?我的建议
说实话,没有绝对最好的库,只有最适合你项目的库。我个人的选型原则是这样的:
- 小项目或简单接口:用手动解析就够了,没必要引入第三方库增加包体积。
- 中大型项目:优先选Gson。Google出品,稳定可靠,社区活跃,遇到问题容易找到解决方案。
- 对性能有极致要求:选FastJson。但要做好混淆配置和循环引用的处理。
- 团队已有技术栈:如果团队之前一直在用某个库,那就继续用,不要为了换而换。
嗯,这里还要补充一点。不管用哪种方式,一定要做异常处理。网络数据是不可信的,服务器可能返回格式错误的JSON,也可能字段缺失。我在项目中见过太多因为JSON解析异常导致App崩溃的案例了。所以,try-catch一定要写,而且最好在catch里做降级处理,比如显示默认数据或者提示用户刷新。
好了,JSON解析这块的内容就讲到这里。三种方式各有优劣,关键是要理解它们的原理和适用场景。动手写几个Demo试试,很快就能掌握。