【Android】JSONObject和Gson的使用
三三要成为安卓糕手
一:JSONObject介绍
JSON常见格式
{
"name": "Alice",
"age": 30,
"isStudent": false,
"address": {
"city": "New York",
"zip": "10001"
},
"courses": ["Math", "Science", "History"],
"grades": [85, 90, 92],
"graduated": null
}
1:利用创建Json数据
/*** 使用JSONObject完成json数据的创建** {* "name": "Alice",* "age": 30,* "isStudent": false,* "address": {* "city": "New York",* "zip": "10001"* },* "courses": ["Math", "Science", "History"],* "grades": [85, 90, 92],* "graduated": null* }*/private void createJSON(){JSONObject jsonObject = new JSONObject();try {//放一些常规的key_value值jsonObject.put("name","Alice");jsonObject.put("age",30);jsonObject.put("isStudent", false);//嵌套一个JSON对象JSONObject addressJSON = new JSONObject();addressJSON.put("city","New York");addressJSON.put("zip" , "10001");jsonObject.put("address" , addressJSON);//放一个json数组,类型为stringJSONArray course = new JSONArray();course.put("Math");course.put("Science");course.put("History");jsonObject.put("courses",course);//放一个json数组,类型为intJSONArray grades = new JSONArray();grades.put(85);grades.put(90);grades.put(92);jsonObject.put("grades",grades);jsonObject.put("graduated",null);//把得到的JSON转化为字符串,打印日志查看效果String string = jsonObject.toString();Log.i(TAG, "createJSON: " + string);} catch (JSONException e) {throw new RuntimeException(e);}}
-
put方法放键值对:Json本来就是键值对的形式,所以这里对类型没有要求
-
放一个对象:其实就是一个Json嵌套一个Json
-
放Json数组:这里实例化的对象是JSONArray(),然后put方法往里面放就行了
-
转化为字符串:用toString()方法即可
2:获取JSON中的属性
private void getJSON(){String json = "{\"name\":\"Alice\",\"age\":30,\"isStudent\":false,\"address\":{\"city\":\"New York\",\"zip\":\"10001\"},\"courses\":[\"Math\",\"Science\",\"History\"],\"grades\":[85,90,92]}";//try {JSONObject jsonObject = new JSONObject(json);//想获取key对应的value,就要用对应类型的get方法String name = jsonObject.getString("name");Log.i(TAG, "getJSON: name =" + name);int age = jsonObject.getInt("age");Log.i(TAG, "getJSON: age = " + age);boolean isStudent = jsonObject.getBoolean("isStudent");Log.i(TAG, "getJSON: isStudent = " + isStudent);JSONObject addressObject = jsonObject.getJSONObject("address");String city = addressObject.getString("city");Log.i(TAG, "getJSON: city = " + city);JSONArray coursesArray = jsonObject.getJSONArray("courses");String course0 = coursesArray.getString(0);Log.i(TAG, "getJSON: 第一个课程是"+course0);// String string = jsonObject.getString("graduated");
// Log.i(TAG, "getJSON: "+string);} catch (JSONException e) {throw new RuntimeException(e);}}
- 实例化JSONObject的时候需要传入JSON字符串
- 想获取key对应的value,就要用对应类型的get方法
二:Gson介绍
1:依赖
implementation ("com.google.code.gson:gson:2.11.0")
Gson 是 Google 开发的一个 Java 库,主要用于在 Java 对象和 JSON 数据之间进行相互转换,它提供了简单易用的 API 来处理 JSON 序列化(将 Java 对象转为 JSON 字符串)和反序列化(将 JSON 字符串转为 Java 对象)操作。
2:利用Gson创建JSON字符串
private void gsonCreateJSON(){//创建Student对象Student student = new Student();student.setName("老龙");student.setAge(19);student.setStudent(true);Student.Address address = new Student.Address();address.setCity("新疆");address.setZip("798");student.setAddress(address);student.setCourses(new String[]{"数学","计算机与科学"});student.setGrades(new Integer[]{100,120});//转化为JSON字符串Gson gson = new Gson();String json = gson.toJson(student);Log.i(TAG, "gsonCreateJSON: " + json);}
效果如下:
3:利用Gson获取JSON中的属性
private void gsonGetJSON(){String json = "{\"address\":{\"city\":\"新疆\",\"zip\":\"798\"},\"age\":19,\"courses\":[\"数学\",\"计算机与科学\"],\"grades\":[100,120],\"isStudent\":true,\"name\":\"老龙\"}";//相当于把这个JSON字符串解析java对象,在通过get方法获取内部的数据Gson gson = new Gson();Student student = gson.fromJson(json, Student.class);String name = student.getName();Integer[] grades = student.getGrades();Log.i(TAG, "gsonCreateJSON: name = " + name);Log.i(TAG, "gsonCreateJSON: grades[1] = " + grades[1])}
优化:之前在http,封装json请求体时就可以创建一个实体类,解析成一个json字符串
注意:解析字符串的时候不要带多余的东西
三:安卓网络通信总结
对比维度 | JSONObject | HttpUrlConnection | OkHttp | Retrofit2 |
---|---|---|---|---|
核心功能定位 | Android 原生 JSON 解析 / 构建工具,仅处理 JSON 数据(无 HTTP 能力) | Java 原生 HTTP 通信工具,用于发起 HTTP 请求 / 接收响应,需手动处理 JSON 和线程 | 第三方 HTTP 客户端(Square 开发),封装 HttpUrlConnection,简化 HTTP 操作 | 基于 OkHttp 的 RESTful API 框架,通过注解 + 接口化方式封装 HTTP 请求,自动处理 JSON 序列化 / 反序列化 |
JSON 处理能力 | ||||
- 解析 JSON(从字符串到对象) | 需手动调用getXXX() 方法(如getString("name") 、getJSONObject("address") ),嵌套结构需逐层解析(见getJSON() 方法),无类型安全 | 仅接收 HTTP 响应的 JSON 字符串,需依赖第三方库(如 Gson)手动解析(代码中未体现,需额外处理) | 仅接收 HTTP 响应的 JSON 字符串,需依赖 Gson 手动调用fromJson() 解析(见sendPostRequest() 中ResLogin resLogin = new Gson().fromJson(json, ResLogin.class) ) | 集成GsonConverterFactory 后,自动将 JSON 响应解析为指定 JavaBean(如UserInfoQuery ),无需手动调用 Gson(见sendGetRequest() 中直接获取response.body().getData().getUser().getNickname() ) |
- 构建 JSON(从对象到字符串) | 需手动调用put() 方法(如jsonObject.put("name","Alice") ),嵌套对象 / 数组需手动创建JSONObject /JSONArray (见createJSON() 方法) | 需手动拼接 JSON 字符串(如"{ \"account\": \"" + account + "\",\"password\": \"" + password + "\" }" ),易出错 | 依赖 Gson 调用toJson() 将 JavaBean(如ReqLogin )转为 JSON 字符串(见sendPostRequest() 中new Gson().toJson(new ReqLogin(account, password)) ) | 自动将 JavaBean(如ReqLogin )序列化为 JSON 请求体,无需手动处理(仅需在接口方法中传入 JavaBean 参数) |
- 类型安全 | 无,需手动判断数据类型(如getInt("age") 若字段为字符串会抛异常) | 无,JSON 字符串解析需手动保证类型匹配 | 依赖 Gson 实现类型安全,但需手动指定目标类 | 完全类型安全,接口方法返回值直接指定响应 JavaBean 类型(如Call<UserInfoQuery> ) |
GET 请求实现 | ||||
- 核心步骤 | 无 HTTP 能力,无法发起 GET 请求 | 1. 手动创建URL 对象;2. 调用 openConnection() 获取HttpURLConnection ;3. 手动设置请求方法( setRequestMethod("GET") )、超时时间;4. 手动获取 InputStream ,通过BufferedReader 读取响应;5. 手动关闭连接(见 sendGetRequest() 方法) | 1. 构建OkHttpClient (可配置超时);2. 构建 Request 对象(指定 URL 和GET 方法);3. 调用 okHttpClient.newCall(request) 获取Call ;4. 调用 enqueue() 异步执行,在Callback 中处理响应(见sendGetRequest() 方法) | 1. 构建Retrofit (指定 BaseURL 和转换器);2. 定义接口(如 ApiService 的getUserInfo(String userId, String type) ),用@GET 注解指定接口路径和参数;3. 调用接口方法获取 Call ;4. 调用 enqueue() 处理响应(见sendGetRequest() 方法) |
- 线程处理 | 无 | 需手动创建子线程(new Thread(new Runnable() { ... }) ),更新 UI 需手动调用runOnUiThread() | 自动在子线程执行请求,Callback 回调在子线程,更新 UI 需手动调用runOnUiThread() | 自动在子线程执行请求,Callback 回调在子线程,更新 UI 需手动调用runOnUiThread() (代码中Toast 直接调用,因onResponse 已在主线程?实际 Retrofit 默认回调在子线程,代码中可能简化处理) |
- 参数拼接 | 无 | 需手动拼接 URL 参数(如"http://...?user_id=" + id + "&type=archives" ) | 需手动拼接 URL 参数(同 HttpUrlConnection)或通过HttpUrl.Builder 构建 URL | 自动拼接参数:通过@Query 注解(如getUserInfo(@Query("user_id") String userId, @Query("type") String type) ),无需手动拼接 |
POST 请求实现 | ||||
- 核心步骤 | 无 HTTP 能力,无法发起 POST 请求 | 1. 同 GET 步骤 1-3,额外设置setDoOutput(true) 允许输出请求体;2. 手动设置请求头( Content-Type: application/json );3. 手动获取 OutputStream ,写入 JSON 字符串;4. 同 GET 步骤 4-5(见 SendPostRequest() 方法) | 1. 同 GET 步骤 1; 2. 构建 RequestBody (指定 JSON 媒体类型和 JSON 字符串);3. 构建 Request 对象(指定 URL 和post(requestBody) );4. 同 GET 步骤 3-4(见 sendPostRequest() 方法) | 1. 同 GET 步骤 1; 2. 定义接口(如 ApiService 的login(@Body ReqLogin reqLogin) ),用@POST 注解指定路径,@Body 指定请求体;3. 同 GET 步骤 3-4(见 sendPostRequest() 方法) |
- 请求体处理 | 无 | 需手动拼接 JSON 字符串并转为字节流写入(易出错,如引号转义) | 需手动将 JavaBean 转为 JSON 字符串,再封装为RequestBody | 自动将@Body 注解的 JavaBean(如ReqLogin )转为 JSON 请求体,无需手动处理 |
- 响应处理 | 无 | 手动读取响应流,需手动解析 JSON 字符串 | 在Callback 中读取response.body().string() ,再手动用 Gson 解析 | 在Callback 中直接获取response.body() (已自动解析为 JavaBean) |
优缺点 | ||||
- 优点 | 1. 原生 API,无需依赖第三方库; 2. 轻量,仅处理 JSON 时性能开销小 | 1. 原生 API,无需依赖第三方库; 2. 完全可控,可自定义所有 HTTP 细节 | 1. 封装完善,简化 HTTP 操作(如自动处理连接池、重定向); 2. 支持同步 / 异步请求; 3. 内置超时、拦截器等实用功能 | 1. 接口化编程,代码结构清晰(分离 API 定义和实现); 2. 自动处理 JSON 序列化 / 反序列化; 3. 支持多种转换器(Gson、Jackson 等); 4. 支持 RxJava、协程等异步框架 |
- 缺点 | 1. 无 HTTP 能力,需配合其他工具使用; 2. 手动解析 / 构建 JSON 代码繁琐,易出错; 3. 无类型安全 | 1. 代码冗余(手动处理流、线程、参数拼接); 2. 无默认 JSON 处理,需额外集成; 3. 不支持连接池,性能较差 | 1. 仍需手动处理 JSON 序列化 / 反序列化(依赖 Gson); 2. 多接口场景下代码仍需重复构建 Request 和Callback | 1. 依赖 Retrofit+OkHttp + 转换器,包体积较大; 2. 简单请求场景下配置稍复杂; 3. 灵活性较低(复杂 HTTP 场景需自定义拦截器) |
适用场景 | 1. 仅需单独处理 JSON 数据(如本地 JSON 字符串解析 / 构建); 2. 轻量级场景,不依赖第三方库 | 1. 学习 HTTP 原理(理解底层流程); 2. 极简场景,不允许引入第三方库; 3. 对 HTTP 细节有高度自定义需求 | 1. 需简化 HTTP 操作,但无需接口化封装的场景; 2. 需灵活处理 HTTP 细节(如自定义拦截器、请求头); 3. 中小型项目的网络请求 | 1. 大型项目,需统一管理 API 接口; 2. RESTful API 场景,需规范请求格式; 3. 需集成 RxJava / 协程实现复杂异步逻辑; 4. 追求代码可维护性和类型安全 |