Last Updated: February 25, 2016
·
4.188K
· partition

SharedPreferences - the right way

SharedPreferences provides easy way to store persist simple values on device's storage. We use it often to store some user's or application's preferences and share it between many places - like multiple Activities.

What we're usually doing is accessing SharedPreferences from Activity's or Service's methods. Like here:

protected void onCreate(Bundle savedInstanceState) {

  SharedPreferences prefs = getSharedPreferences(NAME, Context.MODE_PRIVATE);
  prefs.edit().putLong(MY_ID, mId).commit();
  // or reading
  mId = prefs.getLong(MY_ID, DEFAULT_VALUE);    
}

Of course, when we share MYID value between many places we have to repeat that code all around. And then, for example, our MYID changed and it's not long anymore - it's String. What we do? We replace all that code in every place that is depending on MY_ID. And of course we're not warned by compiler neither by IDE in case we forgot about changing it anywhere.

The solution is to move that SharedPreferences-based code to separated class which can be reused in other places. My example uses RoboGuice, but in case you're not using it in your project and don't want to use it, converting this code is just a matter of passing proper Context via constructor.

public class MyIdManager {

  private final static String MY_ID = "my_id";

  @Inject 
  private SharedPreferences prefs;

  public void storeMyId(long myId) {
    prefs.edit().putLong(MY_ID, myId).commit();
  }

  public boolean isMyIdThere() {
    return prefs.contains(MY_ID);
  }

  public long getMyId() {
    // do whatever you want here, throw exception 
    // if there is no data or return default value
  }

}

SharedPreferences object is automatically injected by RoboGuice so we can avoid writing all that boilerplate code for accessing its instance.
Now we can inject our MyIdManager to our objects (let it be Activity) using simple @Inject annotation:

@Inject
private MyIdManager myIdManager;

This enables you to do many other things. Since your client classes don't depend on SharedPreferences explicitly, you can change your way of persistance from SharedPreferences to SQLiteDatabase, ContentProvider or whatever. You can also change structure of objects you're storing there - if you're interested in persisting more complex objects, composed from 5 strings for example, you can easily pass your structure object to store() method and do all the logic in that method. Last but not least - stubbing class like this is much cleaner and easier than stubbing SharedPreferences. You'll find it useful when you come to test it.