I'm tried to save ArrayList<HashMap<String,Uri>> into json using Gson, but when i read data from json , im noticed that Gson just wiped out data inside HashMaps.
I want to that Gson doesn't wipe my data inside HashMaps anymore.
Here's my saving code in 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();
}
});
And here's code in my MainActivity:
Sry for this tabulation, this is result of many attempts of rewriting code.
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();
}
}
Upd: After claiming an answer(there are 2 answers). I changed HashMap to Data Model class by @Deepak advise, but got exception. And @Marcono1234 explained whats wrong with json that already written in my cache(I don't cleared an app's cache, after swithcing data type) and my Data model. I used ArrayList<ArrayList<DataModel>> instead of ArrayList<HashMap<String,Uri>> . In data model i converted Uri to String .
The underlying issue is that you are trying to serialize
android.net.Uriwith Gson, but Gson has no built-in adapter for it. You can solve this by either replacingUriwith a type which has built-in Gson support, such asString, or by writing a custom GsonTypeAdapterforUri, see this related question. However, you have to register the adapter withGsonBuilder.registerTypeHierarchyAdapter(...)since you want it to handle the subclasses ofUrias well.The following is a more in depth explanation of the issues you encountered, so that troubleshooting future Gson issues becomes easier for you. Some of this are assumptions, which might be slightly incorrect.
With your original code, the reason why the maps where empty and
GsonBuilder.serializeNulls()made them containnullvalues is that:nullbut just omits the members from the JSON objectnullandroid.net.Uriis abstract, so it is conceivable that the actual object you are serializing is an instance of an anonymous class.The current source code for
android.net.Uridoes not actually seem to create anonymous classes, but possibly the Android version you are using is doing it, or maybe there is something different involved which makes Gson think the class is local or anonymous.Regarding the second issue you encountered after you changed your code:
As mentioned above, Gson has no built-in adapter for
android.net.Uri.The reason why you were not seeing this exception with your previous code is that as you mentioned the maps in JSON were empty, so Gson never tried to construct a
android.net.Uri.But with your changed code Gson was serializing the
Urias non-nullvalues (see below for a possible explanation), and therefore also trying to deserialize them again now.Regarding the third issue, after you switched from
UritoString:At this point you had probably managed to serialize the
Urivalues to JSON, probably because when the field had typeUriGson not only considered the runtime class (getClass()), which was serialized asnullpreviously, but also the compile-time classUriof the field[1].But because you still hadn't registered a custom adapter, Gson was using the reflection-based adapter and serialized the
Urias JSON object ({ ... })[2]. So when you then changedUritoStringyou probably still had the old JSON data in the shared preferences so Gson was trying to serialize the previous JSON object{ ... }of theUrias JSON string" ... ".To solve this, just remove the old entry from the shared preferences.
[1]: See Gson's internal
TypeAdapterRuntimeTypeWrapperfor more details.[2]: Relying on the reflection-based adapter for third-party classes should be avoided because you then depend on their implementation details which can change at any point.