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
相关产品推荐
相关产品推荐

