Question

I've the following sample code. The application is installed successfully at first time. However, it throws an error on reinstalling.

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LinkedHashSet<String> planets = new LinkedHashSet<String>();
        planets.add("Earth");
        SharedPreferences prefs = getPreferences(0);
        prefs.edit().putStringSet("planets", planets).commit();
        prefs = getPreferences(0);
        planets = (LinkedHashSet<String>) prefs.getStringSet("planets", new  LinkedHashSet<String>());
    }
}

I've pasted the error produced on reinstalling the application below.

Caused by: java.lang.ClassCastException: java.util.HashSet cannot be cast to java.util.LinkedHashSet at com.example.test.MainActivity.onCreate(MainActivity.java:12)

I want to understand why a saved LinkedHashSet can not be casted back to LinkedHashSet. And why is it automaically being converted to HashSet by Android?

Was it helpful?

Solution

@Ibungo, I think you've misunderstood what SharedPreferences do. You can NOT ask the prefs to save a LinkedHashSet set - you can only ask it to save a general Set. And in return you can get a general Set after that. There are no guarantees that it'll return the same set implementation as yours.

The preferences are just iterating over the set of items you gave them and writing them to the XML store for your application. Thus when you ask for those items it is reading from the XML and creating a new Set - HashSet since it is the most commonly used one.

The only reason you might want a LinkedHashSet, I can think of, is if you want to preserve the insertion order. If this is the case, you might try converting your collection to ArrayList and store it - there is an example here. Alternatively you could save your data to a JSONArray and store it as a String.

OTHER TIPS

Change your code to use a basic HashSet:

HashSet<String> planets = new LinkedHashSet<String>();
planets.add("Earth");
SharedPreferences prefs = getPreferences(0);
prefs.edit().putStringSet("planets", planets).commit();
prefs = getPreferences(0);
planets = prefs.getStringSet("planets", new  LinkedHashSet<String>());

Side note: Keep in mind that SharedPreferences.getStringSet() is available in API11+ only.

The reason why your Set is converted to a HashSet can be found in Android's source code:

public Editor putStringSet(String key, Set<String> values) {
    synchronized (this) {
        mModified.put(key,
            (values == null) ? null : new HashSet<String>(values));
        return this;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top