Android JSON数据解析

在 Android 开发中,JSON(JavaScript Object Notation)是网络请求中最常见的数据格式,用于从服务器获取数据或解析本地 JSON 文件。Android 提供了多种方式解析 JSON 数据,包括原生的 JSONObjectJSONArray,以及第三方库如 GsonMoshi。以下是 Android JSON 数据解析的详细学习指南,涵盖解析方法、代码示例、结合 HTTP 请求、注意事项和实践建议。


一、JSON 解析方法概述

Android 支持以下主要 JSON 解析方式:

  1. JSONObject 和 JSONArray
  • 特点:Android 原生提供的 JSON 解析类,基于 org.json 包。
  • 优点:无需额外依赖,简单易用。
  • 缺点:手动解析代码冗长,易出错,不支持复杂对象映射。
  • 适用场景:简单 JSON 数据解析,快速原型开发。
  1. Gson
  • 特点:Google 提供的开源库,将 JSON 自动映射到 Java/Kotlin 对象。
  • 优点:代码简洁,支持复杂对象、自定义序列化/反序列化。
  • 缺点:需添加依赖,性能略低于 Moshi。
  • 适用场景:大多数 Android 项目,适合复杂 JSON 结构。
  1. Moshi
  • 特点:Square 提供的轻量级 JSON 解析库,类似 Gson 但更现代。
  • 优点:性能高,支持 Kotlin(通过反射或代码生成),类型安全。
  • 缺点:需添加依赖,学习曲线稍陡。
  • 适用场景:Kotlin 项目,追求高性能或类型安全的场景。
  1. Jackson(较少使用):
  • 特点:功能强大的 JSON 解析库,支持流式解析。
  • 优点:适合大型 JSON 文件或复杂场景。
  • 缺点:配置复杂,依赖较重。
  • 适用场景:特殊需求或跨平台项目。

二、准备工作

  1. 网络权限(如从网络获取 JSON 数据):
    AndroidManifest.xml 中添加:
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  1. 示例 JSON 数据
    假设以下 JSON 数据用于解析:
   {
       "users": [
           {
               "id": 1,
               "name": "Alice",
               "age": 25
           },
           {
               "id": 2,
               "name": "Bob",
               "age": 30
           }
       ]
   }
  1. 数据来源
  • 网络请求:通过 HttpURLConnection、OkHttp 或 Retrofit 获取 JSON 数据。
  • 本地文件:将 JSON 文件放入 res/rawassets 目录。
  • 字符串:直接解析 JSON 字符串。
  1. 添加依赖(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 解析方法详解与代码示例

以下是使用 JSONObjectGsonMoshi 解析上述 JSON 的代码示例。

1. 使用 JSONObject 和 JSONArray

JSONObjectJSONArray 是 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。

六、注意事项

  1. 异步处理
  • JSON 解析通常与网络请求结合,必须在子线程执行,避免 NetworkOnMainThreadException
  • 使用 Thread、AsyncTask(已废弃)或 Kotlin 协程。
  1. 错误处理
  • 处理 JSONExceptionJSONObject)、JsonParseException(Gson)或 IOException(Moshi)。
  • 检查 HTTP 状态码和 JSON 格式是否正确。
  • 示例:
    java try { JSONObject jsonObject = new JSONObject(jsonString); } catch (JSONException e) { Log.e("Error", "Invalid JSON: " + e.getMessage()); }
  1. 资源释放
  • 关闭 InputStreamHttpURLConnection
  • 示例:
    java inputStream.close(); conn.disconnect();
  1. 性能优化
  • 使用 Gson 或 Moshi 映射对象,减少手动解析代码。
  • 缓存解析结果,减少重复解析。
  • 对于大型 JSON,考虑流式解析(如 Jackson 的 JsonParser)。
  1. 安全性
  • 验证 JSON 数据来源,避免解析恶意数据。
  • 使用 @SerializedName(Gson)或 @Json(Moshi)确保字段映射正确。
  1. 编码处理
  • 确保 JSON 数据编码为 UTF-8:
    java String jsonString = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")) .lines().collect(Collectors.joining("\n"));

七、学习建议与实践

  1. 学习路径
  • 了解 JSON 结构(对象、数组、嵌套)。
  • 掌握 JSONObjectJSONArray 的基本使用。
  • 学习 Gson 自动映射对象,处理复杂 JSON。
  • 在 Kotlin 项目中使用 Moshi,结合协程。
  • 结合 HttpURLConnection 或 OkHttp 获取 JSON 数据。
  1. 实践项目
  • 简单项目:调用公开 API(如 OpenWeatherMap),解析天气 JSON 数据。
  • 进阶项目:实现用户列表应用,解析嵌套 JSON,显示在 RecyclerView。
  • 本地文件:将 JSON 文件放入 res/rawassets,练习解析。
  1. 调试工具
  • 使用 Postman 测试 JSON API,验证响应。
  • 使用 Charles 抓包,分析 JSON 数据。
  • 使用 Android Studio 的 Logcat 查看解析结果。
  1. 推荐资源
  • 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 序列化)、第三方库对比或特定场景的讲解,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注