UPDATE: It looks like the code for today was accidentally labeled DayTwentyOne instead of DayTwentyTwo. I'll go back and fix this as soon as I have a chance.

Today’s entry in 31 Days of Android begins a three day sub-series on data storage and persistence.  Today’s topic will focus on Shared Preferences.  Shared Preferences are used for storing key-value pairs of primitive data types.  Included in these primitive types are:  booleans, floats, ints, longs, and strings.  If you want to store any complex types such as your own class objects, you would need to manually do a mapping.  You can download the source code we’ll start today with here.

Storing Data in Shared Preferences

Let’s try adding the code to your application so that whenever it loads, the EditText and TextView are filled with whatever the last text was that you had entered when the button was tapped.  Open up the DayTwentyOneActivity.java file and find the onClickListener for button1.  All you’re doing right now is setting lblTextViewOne’s text property to match editText1’s text property.  Here, you need to get a reference to the SharedPreferences Editor.  Once you have a reference to that you can put your data into it.  Finally, you need to commit any changes.  Let’s look at what the code looks like:

button1.setOnClickListener(new OnClickListener() {            
    public void onClick(View v) {
        lblTextViewOne.setText(editText1.getText());    
        SharedPreferences settings = getSharedPreferences("MyPreferencesFileName", 0);
        SharedPreferences.Editor preferencesEditor = settings.edit();
        preferencesEditor.putString("OurText", editText1.getText().toString());
        preferencesEditor.commit();
    }
});

First, you’re getting the reference to SharedPreferences.  The getSharedPreferences method is available because you’re currently inside of the Activity context.  You’re passing in a file name and a mode.  It would be a smart idea to move the file name into a constant so you don’t have to try entering the same text name in multiple places.  The mode you’re passing in above is 0 or MODE_PRIVATE which is the default and means the file can only be accessed by your application.  MODE_WORLD_READABLE (1) means that all other applications have read access to it and MODE_WORLD_WRITEABLE (2) means that all other applications have both read and write access.  Lastly, MODE_MULTI_PROCESS (4) can be used if you need multiple processes to have access to the shared preferences file.  MODE_MULTI_PROCESS was the default behavior in Android 2.3 and earlier.  In versions newer than 2.3, you need to explicitly set it to be multi process capable.

After you get a reference to SharedPreferences you then need to get the Editor out of it.  After that, you can call any of the put* methods on the Editor object to put data into it.  Lastly, you need to call commit() to write those changes back to the file.  commit() is a synchronous operation so you will be notified if there are any errors.  Alternateively you could call apply() on your Editor object, however, while this changes the SharedPreferences in memory, it makes the changes to the file on disk asynchronously and doesn’t notify you if there are any issues. 

Reading Back from SharedPreferences

Being able to write to the SharedPreferences file is great, but equally important is being able to read from those preferences.  Let’s look at checking the preferences file when DayTwentyOneActivity is created and setting the TextView and EditText if it had been previously stored:

...
lblTextViewOne = (TextView) findViewById(R.id.lblTextViewOne);
lblTextViewOne.setText(R.string.test_one);//
editText1 = (EditText) findViewById(R.id.editText1);
editText1.setText(R.string.test_one);
 
SharedPreferences settings = getSharedPreferences("MyPreferencesFileName", 0);
String preferencesString = settings.getString("OurText", null);
if (preferencesString != null) {
    lblTextViewOne.setText(preferencesString);
    editText1.setText(preferencesString);
}
...

First you’re getting a reference to lblTextViewOne and editText1 which is the same as before.  Then you’re getting a reference to the SharedPreferences file (again you’re passing in a name right there when you could / should be using a constant).  Since you aren’t editing any settings here, you don’t need to get an instance of the Editor, you can just access the settings.  Each get* method takes in the name of the setting to fetch and what the default value returned should be if that setting doesn’t exist.  So the first time your app runs, since you wouldn’t have stored anything for OurText yet, it would return null.  Then if the preferencesString isn’t null, you can use that value to set the TextView and EditText.  Running your app again, you should see both Views preset to whatever the text was when you last tapped the button;

Reading from SharedPreferences

Clearing SharedPreferences

If you want to give users the ability to clear any preferences you may have saved it’s easy to be done.  Once you get an instance of the Editor you just call clear() on it:

SharedPreferences settings = getSharedPreferences("MyPreferencesFileName", 0);
SharedPreferences.Editor preferencesEditor = settings.edit();
preferencesEditor.clear();
preferencesEditor.commit();

You still need to call commit() after you’ve cleared the preferences.  Also, if you set any preferences after you hit clear() but before you hit commit(), those will still be stored. 

Removing a Preference

Instead of clearing all preferences, you also have the option to remove an individual one:

SharedPreferences settings = getSharedPreferences("MyPreferencesFileName", 0);
SharedPreferences.Editor preferencesEditor = settings.edit();
preferencesEditor.remove("OurText");
preferencesEditor.commit();

Note that again you need to call commit() after you’ve called remove.

A Couple Things to Note

There is no reason you can’t use multiple preference files in your application.  In the examples above, you passed in “MyPreferencesFileName” whenever getting a reference to SharedPreferences.  However, you could just as easily use different file names in different activities or whatever you need.  It might become complicated to use multiple preference file names but it’s at your disposal.

When it comes to reading and writing preference files from other applications, you don’t need to do anything differently.  You just need to know the name of the preferences file that you need (and have) access to. 

One last and very important thing to know is that use’s have access to clear the SharedPreferences even if you don’t give them access in your application.  On your device, if you go to Settings –> Applications –> Manage Applications –> Your App you’ll see a button to “Clear Data”.  Clicking this clears any data your app has saved, including SharedPreferences:

clear data in settings

You can download the code we ended up with after today’s work here.


Chris Risner