Gain flexibility with generic shared preferences for Android

Ali Alp
4 min readMar 10, 2019

If you have landed here, you have been exposed to the hardship of keeping the Shared Preferences of Android inline. This article will demonstrate a practical method of abstracting all the possible read and write methods for Shared Preference into a simple generic class.

Background

Basically, Shared Preference is a XML file which is acting as a small storage mean for the user’s preferences(settings). while developing an Android application, there are plenty of features or settings which are tightly bounded to the user’s taste, like the colors, themes,fonts,ringtones and etc therefore these preferences need to be saved somewhere to be retrieved on the next execution of the application and that is when the need for a small storage comes to the surface. Android has offered a simple mechanism to achieve the storage of the user’s preferences by introducing the Shared Preferences library.

A simple storage of a setting like the background color goes like this

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(applicationContext);
SharedPreferences.Editor editor = sp.edit();
editor.putString("background_color", "green");editor.apply();

Then Android will save it in /data/data/YOUR_APP_PACKAGE_NAME/shared_prefs/YOUR_APP_PACKAGE_NAME_preferences.xml like this

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="background_color">green</string>
</map>

and later the value of the “background_color” can be retrieved from the Shared Preferences like this

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(applicationContext);String defaultValue="white";
String Value = sp.getString("background_color", defaultValue);

Issue

As it can be seen above for storing the string value in the shared preferences, the putString method needs to be called as well as getString method for retrieving it. Seems pretty straight forward till the application begins to grow and the number of the preferences which it requires to store increase with it.

On the other hand, for storing Boolean, putBooean()/getBoolean() needs to be called innorder to store and retrieve of the preferences respectively.

Solution

The first solution which will pop up is to use a static helper class to take care of this operation, therefore for retrieving/storing String values from and to shared preferences something like the code below will be required

private static String getPrefString(Context context,String prefName,String defaultValue){
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String ret = sp.getString(prefName, defaultValue);
return ret;
}

private static void setPrefString(Context context,String prefName,String value){
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();
editor.putString(prefName, value);
editor.apply();
}

Furthermore for Boolean, StringSet, Float, Long and Integer, two methods each will be required as well (totally 12 methods) in order to be able to handle the storage/retrieval of all the possible types which one can call it is messy and unnecessary.

Another solution is to make the use of Generics like the code below

public class PrefManager<T> {

private Context context;

public PrefManager(Context context) {
this.context = context;
}

/**
* Set any type of shared preferences value
*
@param key of the shared preferences which the caller is desire to set
*
@param value types:
* Boolean ,
* StringSet,
* String,
* Float,
* Long,
* Int
*/
public void set(String key, T value) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();

if (value instanceof Boolean) {
editor.putBoolean(key, (Boolean) value);
}
else if (value instanceof Set) {
editor.putStringSet(key, (Set<String>) value);
}
else if (value instanceof String) {
editor.putString(key, (String) value);
}
else if (value instanceof Float) {
editor.putFloat(key, (Float) value);
}
else if (value instanceof Long) {
editor.putLong(key, (Long) value);
}
else if (value instanceof Integer) {
editor.putInt(key, (Integer) value);
}

editor.apply();
}


/**
* Get any type of value from the shared preference
*
@param key the key of the shared preference
*
@param defaultValue types:
* Boolean ,
* StringSet,
* String,
* Float,
* Long,
* Int
*
@return same type of the default value which has been passed in
*/
public T get(String key, T defaultValue) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);

if (defaultValue instanceof Boolean) {
Boolean ret = sp.getBoolean(key, (Boolean) defaultValue);
return (T) ret;
}
else if (defaultValue instanceof Collection) {
Set<String> result = sp.getStringSet(key, new HashSet<String>());
return (T) result;
}
else if (defaultValue instanceof String) {
String ret = sp.getString(key, (String) defaultValue);
return (T) ret;
}
else if (defaultValue instanceof Float) {
Float result = sp.getFloat(key, (Float) defaultValue);
return (T) result;
}
else if (defaultValue instanceof Long) {
Long result = sp.getLong(key, (Long) defaultValue);
return (T) result;
}
else if (defaultValue instanceof Integer) {
Integer result = sp.getInt(key, (Integer) defaultValue);
return (T) result;
}

return null;
}
}

And it can be consumed for storing data as follows

new PrefManager<String>(applicationContext).set("background_color","green");

and for retrieving it as follows

new PrefManager<String>(applicationContext).get("background_color","white");

As it can be seen with only two methods all the possible data types are being handled moreover the usage is clean,practical and self explanatory. I hope you have found this way of storing/retrieving data from/to shared preferences useful as much as I did :)

--

--

Ali Alp

“Take it easy” is nonsense , take it as hard as you can and don’t let it go :)