You need to enable JavaScript to run this app. Android:如何将JSON URL拉取的JSONObject存入SharedPreferences
优惠活动
大模型
产品
解决方案
定价
更多

Android:如何将JSON URL拉取的JSONObject存入SharedPreferences

实现逻辑说明

SharedPreferences 仅支持存储基础类型、字符串、字符串集合这类简单数据,无需为单条降雨记录拆分大量独立存储键,最稳妥且适合新手的实现方式是:将所有降雨记录整体序列化为JSON字符串存入,读取时反序列化为列表,自动完成去重、10条上限裁剪、过期旧数据淘汰的流程。

第一步:fetchData 类基础改造

首先需要为异步任务传入上下文,才能获取SharedPreferences实例,改造方式为给类增加构造方法,使用ApplicationContext避免内存泄漏:

  1. 补充需要的导入:
import android.content.Context;
import android.content.SharedPreferences;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
  1. 为类增加成员变量与构造方法:
public class fetchData extends AsyncTask<Void,Void,Void> {
    // 新增:持有应用上下文,用于获取SharedPreferences
    private final Context context;
    String data = "";
    private TextView setText;

    // 新增构造方法
    public fetchData(Context context) {
        this.context = context.getApplicationContext();
    }

第二步:在数据解析流程中加入存储、清理逻辑

将原来的onPostExecute方法替换为带存储逻辑的版本,核心流程是:读取本地已有记录 → 合并新拉取的5天数据、按日期去重 → 按日期从新到旧排序 → 仅保留最新的10条记录 → 序列化后存回SharedPreferences:

@Override
protected void onPostExecute(Void aVoid) {
    super.onPostExecute(aVoid);
    StringBuilder stringBuilder = new StringBuilder();

    try {
        // 初始化SharedPreferences实例,单独用RainStorage文件名存储降雨数据
        SharedPreferences sp = context.getSharedPreferences("RainStorage", Context.MODE_PRIVATE);
        // 读取本地已存的降雨记录,没有则默认是空JSON数组
        String existRecordsJson = sp.getString("rain_record_list", "[]");
        JSONArray existRecords = new JSONArray(existRecordsJson);

        // 用临时列表存储合并后的所有记录,方便做去重、排序
        List<JSONObject> mergedList = new ArrayList<>();
        for (int i = 0; i < existRecords.length(); i++) {
            mergedList.add(existRecords.getJSONObject(i));
        }

        // 原有JSON解析逻辑不变
        JSONObject jsonData = new JSONObject(data);
        JSONObject forecast = jsonData.getJSONObject("forecast");
        JSONArray fivedayforecast = forecast.getJSONArray("fivedayforecast");

        // 遍历新拉取的5天数据,完成去重合并
        for (int i = 0; i < fivedayforecast.length(); i++) {
            JSONObject newRecord = fivedayforecast.getJSONObject(i);
            String newDate = newRecord.getString("day");
            boolean isDuplicate = false;

            // 检查本地已有记录是否存在同一天的数据,存在则替换为最新值
            for (int j = 0; j < mergedList.size(); j++) {
                JSONObject oldRecord = mergedList.get(j);
                String oldDate = oldRecord.getString("day");
                if (oldDate.equals(newDate)) {
                    mergedList.set(j, newRecord);
                    isDuplicate = true;
                    break;
                }
            }
            // 无重复则直接新增到合并列表
            if (!isDuplicate) {
                mergedList.add(newRecord);
            }

            // 保留原有TextView展示逻辑
            String datum = newRecord.getString("day");
            String mmRainMin = newRecord.getString("mmRainMin");
            stringBuilder.append("The amount of rain on " + datum + " is " + mmRainMin + " mm" + "\n");
            MainActivity.data.setText(stringBuilder.toString());
            Log.e("mmRainMin", mmRainMin);
        }

        // 按日期从新到旧排序,因为接口返回的day是yyyy-MM-dd格式,直接字符串比较即可正确排序
        Collections.sort(mergedList, (o1, o2) -> {
            try {
                String date1 = o1.getString("day");
                String date2 = o2.getString("day");
                return date2.compareTo(date1);
            } catch (JSONException e) {
                e.printStackTrace();
                return 0;
            }
        });

        // 裁剪为最多10条,超出的旧数据自动丢弃
        JSONArray finalRecords = new JSONArray();
        int keepCount = Math.min(10, mergedList.size());
        for (int k = 0; k < keepCount; k++) {
            finalRecords.put(mergedList.get(k));
        }

        // 将最终的记录序列化后写回SharedPreferences
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("rain_record_list", finalRecords.toString());
        editor.apply();

    } catch (JSONException e) {
        e.printStackTrace();
    }
}

第三步:修改MainActivity中触发拉取的代码

因为fetchData现在需要传入Context作为构造参数,原来的实例化代码需要调整:

click.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v){
        // 传入当前Activity的Context
        fetchData process = new fetchData(MainActivity.this);
        process.execute();
    }
});

后续图表展示的适配

做图表时无需复杂解析,直接从SharedPreferences中读取rain_record_list对应的JSON字符串,反序列化为JSONArray后,遍历每条记录取出day和mmRainMin字段,即可作为图表的横轴、纵轴数据源。

内容的提问来源于stack exchange,提问作者kwanka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 18:27:06