You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Gson序列化ArrayList<HashMap<String,Uri>>丢失数据求助

Gson序列化/反序列化ArrayList<HashMap<String,Uri>>丢失数据的解决方法

问题描述

使用Gson将ArrayList<HashMap<String,Uri>>序列化为JSON保存到SharedPreferences,读取反序列化时发现HashMap内的数据被清空,需要解决该问题。

原代码

保存逻辑(ConfigurationActivity)

endPlanConfiguration.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(v.getContext(), MainActivity.class);
        Gson gson = new Gson();
        String arraylist =  gson.toJson(Singleton.getInstance(v.getContext()).getWorkoutPathList());
        SharedPreferences prefs = getSharedPreferences("Workout", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString("WorkoutPathList", arraylist);
        editor.apply();
        startActivity(intent);
        finish();
    }
});

加载逻辑(MainActivity)

public void loadRecView(){
    try {
        SharedPreferences sharedPreferences = getSharedPreferences("Workout", MODE_PRIVATE);
        Gson gson = new Gson();
        String json = sharedPreferences.getString("WorkoutPathList", null);
        workoutList = gson.fromJson(json, new TypeToken<ArrayList<HashMap<String, Uri>>>() {
        }.getType());

        recyclerView.setAdapter(new AdapterToDays(MainActivity.this, workoutList));
    }
    catch (ClassCastException | NullPointerException ex){
        Toast.makeText(MainActivity.this, "Определите план тренировок!", Toast.LENGTH_SHORT).show();
    } 
}

问题根源

Gson默认无法正确处理Uri对象的序列化与反序列化:Uri并非标准JavaBean结构,缺少Gson解析所需的无参构造器和可识别的公开字段,导致序列化时无法保留有效数据,反序列化时只能生成空对象或直接丢失键值对。同时,HashMap的松散结构会进一步增加Gson类型匹配的不确定性。

解决方案

方案1:为Uri自定义TypeAdapter

编写自定义适配器让Gson能正确转换Uri与字符串:

public class UriTypeAdapter extends TypeAdapter<Uri> {
    @Override
    public void write(JsonWriter out, Uri value) throws IOException {
        out.value(value.toString());
    }

    @Override
    public Uri read(JsonReader in) throws IOException {
        return Uri.parse(in.nextString());
    }
}

创建Gson实例时注册该适配器(保存和加载逻辑都要使用这个配置的Gson):

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Uri.class, new UriTypeAdapter())
        .create();

方案2:改用强类型数据模型(推荐)

用自定义数据模型替代HashMap,同时将Uri转为字符串存储,从根源避免类型解析问题:

定义数据模型类

public class WorkoutItem {
    private String tag;
    private String uriStr;

    // Gson需要无参构造器
    public WorkoutItem() {}

    public WorkoutItem(String tag, Uri uri) {
        this.tag = tag;
        this.uriStr = uri.toString();
    }

    // Getter & Setter
    public String getTag() { return tag; }
    public void setTag(String tag) { this.tag = tag; }

    public Uri getUri() { return Uri.parse(uriStr); }
    public void setUriStr(String uriStr) { this.uriStr = uriStr; }
}

修改保存逻辑

将原ArrayList<HashMap<String,Uri>>转换为ArrayList<WorkoutItem>后序列化:

ArrayList<HashMap<String,Uri>> originalList = Singleton.getInstance(v.getContext()).getWorkoutPathList();
ArrayList<WorkoutItem> itemList = new ArrayList<>();
for (HashMap<String,Uri> map : originalList) {
    for (Map.Entry<String,Uri> entry : map.entrySet()) {
        itemList.add(new WorkoutItem(entry.getKey(), entry.getValue()));
    }
}
Gson gson = new Gson();
String arraylist = gson.toJson(itemList);
// 后续保存到SharedPreferences的逻辑不变

修改加载逻辑

直接反序列化为ArrayList<WorkoutItem>:

String json = sharedPreferences.getString("WorkoutPathList", null);
ArrayList<WorkoutItem> itemList = gson.fromJson(json, new TypeToken<ArrayList<WorkoutItem>>() {}.getType());
// 根据需求转换为原结构或直接使用itemList

更新说明

改用数据模型类后曾出现异常,原因是切换数据类型后未清除应用缓存,旧JSON格式与新数据模型不匹配。后续改用ArrayList<ArrayList<DataModel>>结构,并在数据模型中将Uri转为String存储,成功解决异常问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 00:03:16