How to prevent SharedPreferences from loading corrupt data

Viewed 72

I have a custom class with 3 String fields (arg1, arg2, arg3) and getters/setters. In Fragment there are 3 editText fields that create a new Object of custom class. And I also have an ArrayList of custom objects (max capacity is 15, but its usualy around 1-3) that is stored in SharedPreferences.
Everything worked fine until last update in which I only changed some UI design features in xml. Not a single line of Java code was changed, especialy those that have something to do with Custom objects, ArrayList or SharedPrefs.
Now some users, after updating my app, get corrupted first (or in most cases, only) entry of ArrayList, and arg1 is "" or null.
The worst thing is they are displayed the value of arg2 where is explicitly called textView.setText(arg1).

Im saving my SharedPrefs in onStop() and restoring it in onCreate() and I'm using Gson/Json for storing. In 99,9% everything is fine, but after recent update, some users reported this problem.

What's going on, and how to prevent it from happening in the future?

EDIT: What about the fact that I set my ArrayList to be public static, so I can use it elsewhere, would it be a problem? Also since I can't debug production app, I've noticed that either args or their values have moved like MyCustomObject("val1", "val2", "val3") is now MyCustomObject("val2", "val3", "???") I dont know what last value is. Is it val1 or ""

1 Answers

Everything worked fine until last update in which I only changed some UI design features in xml.

UI classes (like your custom UI class with 3 EditText) should not be serialized, because UI classes tend to change over time and it is not the pattern. You should only store/serialize data/object that represents UI states, not the UI objects themselves.

Im saving my SharedPrefs in onStop() and restoring it in onCreate() and I'm using Gson/Json for storing. In 99,9% everything is fine, but after recent update, some users reported this problem.

Suppose, the newer version of a UI class includes an extra member variable. Now, serializing in the newer version will give a different JSON string than the previous version. And as a result, your UI logic might conflict.

Workaround

In this case, you should make ArrayList of the custom class with 3 String fields (arg1, arg2, arg3) and getters/setters, then serialize/deserialize this ArrayList with Gson or any other library. Note that, the following example is basic and not perfect since no associated code provided.

In onCreate(), initialize the UI components with this data. For example:

// Retrieve data and initialize custom data holder by deserializing stored json
CustomObj customObj = gson.get(typeToken, str);
// Use this data to initialize UI components
customUiObj.editText1.setText(customObj.arg1);
customUiObj.editText2.setText(customObj.arg2);
customUiObj.editText3.setText(customObj.arg3);

In onStop(), retrieve data from the UI components to store. For example:

String arg1 = customUiObj.editText1.getText().toString();
String arg2 = customUiObj.editText2.getText().toString();
String arg3 = customUiObj.editText3.getText().toString();
// Now, create a data holder object
CustomObj obj = new CustomObj(arg1, arg2, arg3);
// Serialize this obj
String jsonStr = gson.toJson(customObj);
Related