我尝试使用 Gson 将 ArrayList
我希望 Gson 不再擦除我在 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();
}
}
您可以创建这样的模型,
public class MyModel {
private String name;
private Uri uri;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Uri getUri() {
return uri;
}
public void setUri(Uri uri) {
this.uri = uri;
}
}
您的
HashMap<String, Uri>
可以简化为 List<MyModel>
使用这个简化的列表作为外部列表中的类型。
将
ArrayList<HashMap<String, Uri>>
更改为List<List<MyModel>>
,这样会减少混乱。
然后尝试将传入的数据分配到这个列表中,
SharedPreferences sharedPreferences = getSharedPreferences("Workout", MODE_PRIVATE);
String json = sharedPreferences.getString("WorkoutPathList", null);
List<List<MyModel>> workOutList = new Gson().fromJson(json, new TypeToken<List<List<MyModel>>>() {}.getType());
注意:Gson 转换不会修改/删除我们传递给它的数据。 Singleton 类中的数据检索可能存在问题。核实。另一件重要的事情是,您传递给 Gson 的数据不应该是空字符串,因为您使用了 try catch 块,所以您无法找出问题所在。尝试使用
Exception
而不是 ClassCastException | NullPointerException
,然后记录异常。你可能会得到一些线索。
如果您尚未解决问题,则必须尝试上述代码建议。
祝一切顺利。
根本问题是您正在尝试使用 Gson 序列化
android.net.Uri
,但 Gson 没有内置适配器。您可以通过将 Uri
替换为具有内置 Gson 支持的类型(例如 String
)来解决此问题,或者为 TypeAdapter
编写自定义 Gson Uri
,请参阅此相关问题。但是,您必须使用 GsonBuilder.registerTypeHierarchyAdapter(...)
注册适配器,因为您希望它也处理 Uri
的子类。
以下是对您遇到的问题的更深入的解释,以便您以后更轻松地排查 Gson 问题。其中一些是假设,可能略有不正确。
GsonBuilder.serializeNulls()
使它们包含 null
值的原因是:
null
,只是省略 JSON 对象中的成员null
android.net.Uri
是抽象的,因此可以想象,您正在序列化的实际对象是匿名类的实例。android.net.Uri
的当前源代码实际上似乎并没有创建匿名类,但可能您正在使用的Android版本正在这样做,或者可能涉及到一些不同的东西,使Gson认为该类是本地或匿名的。关于您更改代码后遇到的第二个问题:
抽象类无法实例化!为此类型注册 InstanceCreator 或 TypeAdapter。类名:android.net.Uri
如上所述,Gson 没有内置适配器
android.net.Uri
。android.net.Uri
。Uri
序列化为非 null
值(请参阅下面的可能解释),因此现在也尝试再次反序列化它们。
关于第三个问题,从
Uri
切换到String
后:
IllegalStateException:需要一个字符串,但在第 1 行第 45 列路径 $[0][0].uri 处是 BEGIN_OBJECT
此时,您可能已成功将
Uri
值序列化为 JSON,可能是因为当字段具有类型 Uri
时,Gson 不仅考虑了运行时类 (getClass()
),它之前被序列化为 null
,还有字段[1]的编译时类
Uri
。Uri
序列化为 JSON 对象 ({ ... }
)[2]。因此,当您将 Uri
更改为 String
时,共享首选项中可能仍然有旧的 JSON,因此 Gson 尝试将 { ... }
的先前 JSON 对象 Uri
序列化为 JSON 字符串 " ... "
。
要解决此问题,只需从共享首选项中删除旧条目即可。
TypeAdapterRuntimeTypeWrapper
。
[2]:应该避免依赖第三方类的基于反射的适配器,因为这样您就依赖于它们的实现细节,这些细节可能随时发生变化。