Android:如何将JSON URL拉取的JSONObject存入SharedPreferences
实现逻辑说明
SharedPreferences 仅支持存储基础类型、字符串、字符串集合这类简单数据,无需为单条降雨记录拆分大量独立存储键,最稳妥且适合新手的实现方式是:将所有降雨记录整体序列化为JSON字符串存入,读取时反序列化为列表,自动完成去重、10条上限裁剪、过期旧数据淘汰的流程。
第一步:fetchData 类基础改造
首先需要为异步任务传入上下文,才能获取SharedPreferences实例,改造方式为给类增加构造方法,使用ApplicationContext避免内存泄漏:
- 补充需要的导入:
import android.content.Context; import android.content.SharedPreferences; import java.util.ArrayList; import java.util.Collections; import java.util.List;
- 为类增加成员变量与构造方法:
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
相关产品推荐
相关产品推荐

