《Android 应用开发基础教程》——第十章:使用 Gson 实现网络 JSON 数据解析与对象映射

发布于:2025-05-02 ⋅ 阅读:(38) ⋅ 点赞:(0)

目录

第十章:使用 Gson 实现网络 JSON 数据解析与对象映射

🔹 10.1 什么是 Gson?

🔸 10.2 添加依赖

🔸 10.3 基础使用

✦ 示例 JSON 字符串:

✦ 定义对应的 Java 类:

✦ JSON ➜ 对象(反序列化):

✦ 对象 ➜ JSON(序列化):

🔸 10.4 解析 JSON 数组

✦ 示例 JSON 数组:

✦ Java 代码解析(使用 TypeToken):

🔸 10.5 配合 OkHttp 实战应用

✦ 示例:请求服务器返回 JSON,并转换成对象

✦ 示例实体类 Post:

✅ 小技巧与注意事项

🧪 实战练习建议

习题答案

项目结构

1. MainActivity.java

2. NewsAdapter.java

3. NewsItem.java

4. GsonUtils.java

5. activity_main.xml

6. item_news.xml

总结


第十章:使用 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 注解

🧪 实战练习建议

  1. 请求网络中的新闻 JSON,并展示在 RecyclerView

  2. 把用户输入保存为对象,用 Gson 写入本地文件或 SharedPreferences

  3. 写一个工具类封装 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>

总结

  1. 网络请求:通过 OkHttp 获取新闻 JSON 数据并展示在 RecyclerView 中。
  2. 数据存储
    • 使用 GsonUtils 将用户输入的对象保存到本地文件或 SharedPreferences
    • 提供了多种存储和解析方法(如单个对象、列表等)。
  3. 工具类:封装了 GsonUtils,方便复用。


网站公告

今日签到

点亮在社区的每一天
去签到