Android JSON数据解析
在 Android 开发中,JSON(JavaScript Object Notation)是网络请求中最常见的数据格式,用于从服务器获取数据或解析本地 JSON 文件。Android 提供了多种方式解析 JSON 数据,包括原生的 JSONObject
和 JSONArray
,以及第三方库如 Gson 和 Moshi。以下是 Android JSON 数据解析的详细学习指南,涵盖解析方法、代码示例、结合 HTTP 请求、注意事项和实践建议。
一、JSON 解析方法概述
Android 支持以下主要 JSON 解析方式:
- JSONObject 和 JSONArray:
- 特点:Android 原生提供的 JSON 解析类,基于
org.json
包。 - 优点:无需额外依赖,简单易用。
- 缺点:手动解析代码冗长,易出错,不支持复杂对象映射。
- 适用场景:简单 JSON 数据解析,快速原型开发。
- Gson:
- 特点:Google 提供的开源库,将 JSON 自动映射到 Java/Kotlin 对象。
- 优点:代码简洁,支持复杂对象、自定义序列化/反序列化。
- 缺点:需添加依赖,性能略低于 Moshi。
- 适用场景:大多数 Android 项目,适合复杂 JSON 结构。
- Moshi:
- 特点:Square 提供的轻量级 JSON 解析库,类似 Gson 但更现代。
- 优点:性能高,支持 Kotlin(通过反射或代码生成),类型安全。
- 缺点:需添加依赖,学习曲线稍陡。
- 适用场景:Kotlin 项目,追求高性能或类型安全的场景。
- Jackson(较少使用):
- 特点:功能强大的 JSON 解析库,支持流式解析。
- 优点:适合大型 JSON 文件或复杂场景。
- 缺点:配置复杂,依赖较重。
- 适用场景:特殊需求或跨平台项目。
二、准备工作
- 网络权限(如从网络获取 JSON 数据):
在AndroidManifest.xml
中添加:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- 示例 JSON 数据:
假设以下 JSON 数据用于解析:
{
"users": [
{
"id": 1,
"name": "Alice",
"age": 25
},
{
"id": 2,
"name": "Bob",
"age": 30
}
]
}
- 数据来源:
- 网络请求:通过
HttpURLConnection
、OkHttp 或 Retrofit 获取 JSON 数据。 - 本地文件:将 JSON 文件放入
res/raw
或assets
目录。 - 字符串:直接解析 JSON 字符串。
- 添加依赖(Gson 或 Moshi):
在build.gradle
(app 模块)中添加:
// Gson
implementation 'com.google.code.gson:gson:2.10.1'
// Moshi
implementation 'com.squareup.moshi:moshi:1.15.0'
// Moshi Kotlin 支持(可选)
implementation 'com.squareup.moshi:moshi-kotlin:1.15.0'
三、JSON 解析方法详解与代码示例
以下是使用 JSONObject
、Gson
和 Moshi
解析上述 JSON 的代码示例。
1. 使用 JSONObject 和 JSONArray
JSONObject
和 JSONArray
是 Android 原生的 JSON 解析工具。
- 代码示例:
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class JsonParser {
public static class User {
String id, name, age;
@Override
public String toString() {
return "User{id='" + id + "', name='" + name + "', age='" + age + "'}";
}
}
public static List<User> parseJsonWithJsonObject(String jsonString) throws Exception {
List<User> users = new ArrayList<>();
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray usersArray = jsonObject.getJSONArray("users");
for (int i = 0; i < usersArray.length(); i++) {
JSONObject userObject = usersArray.getJSONObject(i);
User user = new User();
user.id = userObject.getString("id");
user.name = userObject.getString("name");
user.age = userObject.getString("age");
users.add(user);
}
return users;
}
}
- 使用示例(从网络获取 JSON):
new Thread(() -> {
try {
URL url = new URL("https://api.example.com/users.json");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream inputStream = conn.getInputStream();
String jsonString = new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining("\n"));
inputStream.close();
List<JsonParser.User> users = JsonParser.parseJsonWithJsonObject(jsonString);
runOnUiThread(() -> {
for (JsonParser.User user : users) {
Log.d("JsonObject", user.toString());
}
});
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
2. 使用 Gson
Gson 自动将 JSON 映射到 Java/Kotlin 对象,代码简洁。
- 定义模型类:
public class User {
@SerializedName("id")
String id;
@SerializedName("name")
String name;
@SerializedName("age")
String age;
@Override
public String toString() {
return "User{id='" + id + "', name='" + name + "', age='" + age + "'}";
}
}
public class UserResponse {
@SerializedName("users")
List<User> users;
}
- 解析代码:
import com.google.gson.Gson;
import java.io.InputStream;
import java.util.List;
public class GsonParser {
public static List<User> parseJsonWithGson(String jsonString) {
Gson gson = new Gson();
UserResponse response = gson.fromJson(jsonString, UserResponse.class);
return response.users;
}
}
- 使用示例(从本地 assets 文件解析):
new Thread(() -> {
try {
InputStream inputStream = getAssets().open("users.json");
String jsonString = new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining("\n"));
inputStream.close();
List<User> users = GsonParser.parseJsonWithGson(jsonString);
runOnUiThread(() -> {
for (User user : users) {
Log.d("Gson", user.toString());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}).start();
3. 使用 Moshi
Moshi 是现代化的 JSON 解析库,特别适合 Kotlin 项目。
- 定义模型类(Kotlin):
data class User(
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "age") val age: String
)
data class UserResponse(
@Json(name = "users") val users: List<User>
)
- 解析代码(Kotlin):
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import java.io.InputStream
object MoshiParser {
fun parseJsonWithMoshi(jsonString: String): List<User> {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val adapter = moshi.adapter(UserResponse::class.java)
return adapter.fromJson(jsonString)?.users ?: emptyList()
}
}
- 使用示例(从网络获取 JSON,Kotlin 协程):
suspend fun fetchAndParseJson(urlString: String): List<User> = withContext(Dispatchers.IO) {
val url = URL(urlString)
val conn = url.openConnection() as HttpURLConnection
try {
conn.requestMethod = "GET"
conn.setRequestProperty("Accept", "application/json")
if (conn.responseCode == HttpURLConnection.HTTP_OK) {
val jsonString = conn.inputStream.bufferedReader().use { it.readText() }
MoshiParser.parseJsonWithMoshi(jsonString)
} else {
emptyList()
}
} finally {
conn.disconnect()
}
}
// 调用
lifecycleScope.launch {
try {
val users = fetchAndParseJson("https://api.example.com/users.json")
users.forEach { Log.d("Moshi", it.toString()) }
} catch (e: Exception) {
e.printStackTrace()
}
}
四、结合 HttpURLConnection 获取 JSON 数据
以下是使用 HttpURLConnection
获取 JSON 数据并用 Gson 解析的完整示例:
public void fetchAndParseJson(String urlString) {
new Thread(() -> {
HttpURLConnection conn = null;
try {
// 1. 获取 JSON 数据
URL url = new URL(urlString);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
String jsonString = new BufferedReader(new InputStreamReader(conn.getInputStream()))
.lines().collect(Collectors.joining("\n"));
// 2. 解析 JSON
List<User> users = GsonParser.parseJsonWithGson(jsonString);
// 3. 更新 UI
runOnUiThread(() -> {
for (User user : users) {
Log.d("Gson", user.toString());
}
});
} else {
Log.e("Error", "Response Code: " + conn.getResponseCode());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
}).start();
}
五、解析方法对比
解析方法 | 依赖 | 代码复杂性 | 性能 | 适用场景 |
---|---|---|---|---|
JSONObject | 无 | 高 | 中等 | 简单 JSON,快速原型开发 |
Gson | 需要依赖 | 低 | 高 | 复杂 JSON,Java/Kotlin 项目 |
Moshi | 需要依赖 | 低 | 更高 | Kotlin 项目,追求性能 |
Jackson | 需要依赖 | 高 | 高 | 大型 JSON 或跨平台项目 |
- 推荐:Android 项目优先使用 Gson(Java/Kotlin)或 Moshi(Kotlin),简单场景可使用
JSONObject
。 - 选择依据:
- 简单 JSON:使用
JSONObject
。 - 复杂对象映射:使用 Gson 或 Moshi。
- Kotlin 项目:优先 Moshi。
六、注意事项
- 异步处理:
- JSON 解析通常与网络请求结合,必须在子线程执行,避免
NetworkOnMainThreadException
。 - 使用 Thread、AsyncTask(已废弃)或 Kotlin 协程。
- 错误处理:
- 处理
JSONException
(JSONObject
)、JsonParseException
(Gson)或IOException
(Moshi)。 - 检查 HTTP 状态码和 JSON 格式是否正确。
- 示例:
java try { JSONObject jsonObject = new JSONObject(jsonString); } catch (JSONException e) { Log.e("Error", "Invalid JSON: " + e.getMessage()); }
- 资源释放:
- 关闭
InputStream
和HttpURLConnection
。 - 示例:
java inputStream.close(); conn.disconnect();
- 性能优化:
- 使用 Gson 或 Moshi 映射对象,减少手动解析代码。
- 缓存解析结果,减少重复解析。
- 对于大型 JSON,考虑流式解析(如 Jackson 的
JsonParser
)。
- 安全性:
- 验证 JSON 数据来源,避免解析恶意数据。
- 使用
@SerializedName
(Gson)或@Json
(Moshi)确保字段映射正确。
- 编码处理:
- 确保 JSON 数据编码为 UTF-8:
java String jsonString = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")) .lines().collect(Collectors.joining("\n"));
七、学习建议与实践
- 学习路径:
- 了解 JSON 结构(对象、数组、嵌套)。
- 掌握
JSONObject
和JSONArray
的基本使用。 - 学习 Gson 自动映射对象,处理复杂 JSON。
- 在 Kotlin 项目中使用 Moshi,结合协程。
- 结合
HttpURLConnection
或 OkHttp 获取 JSON 数据。
- 实践项目:
- 简单项目:调用公开 API(如 OpenWeatherMap),解析天气 JSON 数据。
- 进阶项目:实现用户列表应用,解析嵌套 JSON,显示在 RecyclerView。
- 本地文件:将 JSON 文件放入
res/raw
或assets
,练习解析。
- 调试工具:
- 使用 Postman 测试 JSON API,验证响应。
- 使用 Charles 抓包,分析 JSON 数据。
- 使用 Android Studio 的 Logcat 查看解析结果。
- 推荐资源:
- Gson 文档:https://github.com/google/gson
- Moshi 文档:https://github.com/square/moshi
- Android 官方文档:https://developer.android.com/reference/org/json/JSONObject
- 实践 API:https://api.github.com/users 或 https://openweathermap.org/api
八、Kotlin 协程与 Retrofit 示例
结合 Retrofit 和 Moshi,异步解析 JSON(Kotlin):
- Retrofit 接口:
interface ApiService {
@GET("users.json")
suspend fun getUsers(): UserResponse
}
- 配置 Retrofit:
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val apiService = retrofit.create(ApiService::class.java)
- 调用和解析:
lifecycleScope.launch {
try {
val users = apiService.getUsers().users
users.forEach { Log.d("Moshi", it.toString()) }
} catch (e: Exception) {
e.printStackTrace()
}
}
九、总结
- 解析方法:
- JSONObject/JSONArray:原生,适合简单 JSON。
- Gson:自动映射,适合复杂 JSON,Java/Kotlin 通用。
- Moshi:轻量高效,适合 Kotlin 项目。
- 结合网络:使用
HttpURLConnection
、OkHttp 或 Retrofit 获取 JSON 数据,异步解析。 - 注意事项:异步处理、错误处理、资源释放、编码一致。
- 推荐:优先使用 Gson 或 Moshi,新项目结合 Retrofit 和协程。
- 实践:调用 JSON API 或解析本地文件,结合调试工具验证。
如果需要更详细的代码示例(如解析复杂嵌套 JSON、自定义 Gson 序列化)、第三方库对比或特定场景的讲解,请告诉我!