目录
第十章:使用 Gson 实现网络 JSON 数据解析与对象映射
第十章:使用 Gson 实现网络 JSON 数据解析与对象映射
在进行网络请求时,服务器返回的数据大多是 JSON 格式。手动解析 JSON 字符串非常繁琐,因此我们通常使用第三方库如 Gson 来将 JSON 数据自动转为 Java 对象,方便开发与维护。
🔹 10.1 什么是 Gson?
Gson 是 Google 提供的 JSON 库,能轻松实现:
JSON ➜ Java 对象(反序列化)
Java 对象 ➜ JSON 字符串(序列化)
🔸 10.2 添加依赖
在 build.gradle
文件中添加:
implementation 'com.google.code.gson:gson:2.10.1'
🔸 10.3 基础使用
✦ 示例 JSON 字符串:
{
"id": 1,
"title": "Gson 教程",
"author": "Alice"
}
✦ 定义对应的 Java 类:
public class Article {
private int id;
private String title;
private String author;
// Getter/Setter 省略,可使用 Lombok 自动生成
}
✦ JSON ➜ 对象(反序列化):
String json = "{\"id\":1,\"title\":\"Gson 教程\",\"author\":\"Alice\"}";
Gson gson = new Gson();
Article article = gson.fromJson(json, Article.class);
Log.d("GSON", "标题:" + article.getTitle());
✦ 对象 ➜ JSON(序列化):
Article article = new Article();
article.setId(2);
article.setTitle("新文章");
article.setAuthor("Bob");
String json = gson.toJson(article);
Log.d("GSON", "JSON字符串:" + json);
🔸 10.4 解析 JSON 数组
✦ 示例 JSON 数组:
[
{"id": 1, "title": "A"},
{"id": 2, "title": "B"}
]
✦ Java 代码解析(使用 TypeToken
):
String jsonArray = "[{\"id\":1,\"title\":\"A\"},{\"id\":2,\"title\":\"B\"}]";
Type listType = new TypeToken<List<Article>>(){}.getType();
List<Article> articles = new Gson().fromJson(jsonArray, listType);
for (Article a : articles) {
Log.d("GSON", a.getTitle());
}
🔸 10.5 配合 OkHttp 实战应用
✦ 示例:请求服务器返回 JSON,并转换成对象
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://jsonplaceholder.typicode.com/posts/1")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string();
// 解析 JSON 到 Java 对象
Gson gson = new Gson();
Post post = gson.fromJson(json, Post.class);
Log.d("GSON", "标题:" + post.getTitle());
}
});
✦ 示例实体类 Post
:
public class Post {
private int userId;
private int id;
private String title;
private String body;
// Getter 和 Setter
}
✅ 小技巧与注意事项
问题 | 建议 |
---|---|
字段名不一致 | 用 @SerializedName("json字段") 标注 |
多层嵌套 JSON | 创建多个内部类解析 |
忽略某些字段 | 使用 transient 或 @Expose 注解 |
🧪 实战练习建议
请求网络中的新闻 JSON,并展示在 RecyclerView
把用户输入保存为对象,用 Gson 写入本地文件或
SharedPreferences
写一个工具类封装
GsonUtils
,实现常规解析函数
📢 下一章预告:
第十一章:Android 中的图片加载与缓存(Glide 使用详解)
习题答案
项目结构
MainActivity.java
NewsAdapter.java
GsonUtils.java
activity_main.xml
item_news.xml
1. MainActivity.java
package com.example.demo;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private NewsAdapter adapter;
private List<NewsItem> newsList;
private OkHttpClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
newsList = new ArrayList<>();
adapter = new NewsAdapter(newsList);
recyclerView.setAdapter(adapter);
client = new OkHttpClient();
fetchNewsData();
}
private void fetchNewsData() {
String url = "https://newsapi.org/v2/top-headlines?country=us&apiKey=YOUR_API_KEY"; // 替换为你的 API 密钥
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(() -> adapter.updateData(new ArrayList<>()));
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
String responseData = response.body().string();
JSONObject jsonObject = new JSONObject(responseData);
JSONArray articles = jsonObject.getJSONArray("articles");
List<NewsItem> newsItems = new ArrayList<>();
for (int i = 0; i < articles.length(); i++) {
JSONObject article = articles.getJSONObject(i);
String title = article.getString("title");
String description = article.getString("description");
newsItems.add(new NewsItem(title, description));
}
runOnUiThread(() -> adapter.updateData(newsItems));
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> adapter.updateData(new ArrayList<>()));
}
} else {
runOnUiThread(() -> adapter.updateData(new ArrayList<>()));
}
}
});
}
}
2. NewsAdapter.java
package com.example.demo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<NewsItem> newsList;
public NewsAdapter(List<NewsItem> newsList) {
this.newsList = newsList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_news, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
NewsItem item = newsList.get(position);
holder.textViewTitle.setText(item.getTitle());
holder.textViewDescription.setText(item.getDescription());
}
@Override
public int getItemCount() {
return newsList.size();
}
public void updateData(List<NewsItem> newData) {
newsList.clear();
newsList.addAll(newData);
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView textViewTitle;
TextView textViewDescription;
public ViewHolder(@NonNull View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.textViewTitle);
textViewDescription = itemView.findViewById(R.id.textViewDescription);
}
}
}
3. NewsItem.java
package com.example.demo;
public class NewsItem {
private String title;
private String description;
public NewsItem(String title, String description) {
this.title = title;
this.description = description;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
}
4. GsonUtils.java
package com.example.demo;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.List;
public class GsonUtils {
private static final Gson gson = new Gson();
// 将对象写入 SharedPreferences
public static void saveObjectToSharedPreferences(Context context, String key, Object object) {
SharedPreferences sharedPreferences = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
String json = gson.toJson(object);
sharedPreferences.edit().putString(key, json).apply();
}
// 从 SharedPreferences 读取对象
public static <T> T getObjectFromSharedPreferences(Context context, String key, Class<T> classOfT) {
SharedPreferences sharedPreferences = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
String json = sharedPreferences.getString(key, null);
return json == null ? null : gson.fromJson(json, classOfT);
}
// 将对象写入本地文件
public static void saveObjectToFile(Context context, String fileName, Object object) {
try (FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE)) {
String json = gson.toJson(object);
fos.write(json.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
// 从本地文件读取对象
public static <T> T getObjectFromFile(Context context, String fileName, Class<T> classOfT) {
try (FileInputStream fis = context.openFileInput(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
StringBuilder json = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
json.append(line);
}
return gson.fromJson(json.toString(), classOfT);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 将列表写入本地文件
public static <T> void saveListToFile(Context context, String fileName, List<T> list) {
Type type = new TypeToken<List<T>>() {}.getType();
try (FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE)) {
String json = gson.toJson(list, type);
fos.write(json.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
// 从本地文件读取列表
public static <T> List<T> getListFromFile(Context context, String fileName, Type type) {
try (FileInputStream fis = context.openFileInput(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
StringBuilder json = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
json.append(line);
}
return gson.fromJson(json.toString(), type);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
5. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
</LinearLayout>
6. item_news.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/textViewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textViewDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Description"
android:textSize="14sp" />
</LinearLayout>
总结
- 网络请求:通过 OkHttp 获取新闻 JSON 数据并展示在
RecyclerView
中。 - 数据存储:
- 使用
GsonUtils
将用户输入的对象保存到本地文件或SharedPreferences
。 - 提供了多种存储和解析方法(如单个对象、列表等)。
- 使用
- 工具类:封装了
GsonUtils
,方便复用。