This practical codelab is part of Unit 4: Saving user data in the Android Developer Fundamentals (Version 2) course. You will get the most value out of this course if you work through the codelabs in sequence:

Introduction

Shared preferences allow you to store small amounts of primitive data as key/value pairs in a file on the device. To get a handle to a preference file, and to read, write, and manage preference data, use the SharedPreferences class. The Android framework manages the shared preferences file itself. The file is accessible to all the components of your app, but it is not accessible to other apps.

The data you save to shared preferences is different from the data in the saved activity state, which you learned about in an earlier chapter:

Use shared preferences only when you need to save a small amount data as simple key/value pairs. To manage larger amounts of persistent app data, use a storage method such as the Room library or an SQL database.

What you should already know

You should be familiar with:

What you'll learn

What you'll do

The HelloSharedPrefs app is another variation of the HelloToast app you created in Lesson 1. It includes buttons to increment the number, to change the background color, and to reset both the number and color to their defaults. The app also uses themes and styles to define the buttons.

You start with the starter app and add shared preferences to the main activity code. You also add a reset button that sets both the count and the background color to the default, and clears the preferences file.

The complete starter app project for this practical is available at HelloSharedPrefs-Starter. In this task you load the project into Android Studio and explore some of the app's key features.

1.1 Open and run the HelloSharedPrefs project

  1. Download the HelloSharedPrefs-Starter code.
  2. Open the project in Android Studio, and build and run the app.

Test the app by trying these steps:

  1. Click the Count button to increment the number in the main text view.
  2. Click any of the color buttons to change the background color of the main text view.
  3. Rotate the device and note that both background color and count are preserved.
  4. Click the Reset button to set the color and count back to the defaults.

Now test what happens when you quit and restart the app:

  1. Force-quit the app using one of these methods:
  1. Re-run the app. The app restarts with the default appearance—the count is 0, and the background color is grey.

1.2 Explore the Activity code

  1. Open MainActivity.
  2. Examine the code.

Note these things:

In this task you save the state of the app to a shared preferences file, and read that data back in when the app is restarted. Because the state data that you save to the shared preferences (the current count and color) are the same data that you preserve in the instance state, you don't have to do it twice. You can replace the instance state altogether with the shared preference state.

2.1 Initialize the preferences

  1. Add member variables to the MainActivity class to hold the name of the shared preferences file, and a reference to a SharedPreferences object.
private SharedPreferences mPreferences;
private String sharedPrefFile = 
   "com.example.android.hellosharedprefs";

You can name your shared preferences file anything you want to, but conventionally it has the same name as the package name of your app.

  1. In the onCreate() method, initialize the shared preferences. Insert this code before the if statement:
mPreferences = getSharedPreferences(sharedPrefFile, MODE_PRIVATE);

The getSharedPreferences() method (from the activity Context) opens the file at the given filename (sharedPrefFile) with the mode MODE_PRIVATE.

Solution code for MainActivity, partial:

public class MainActivity extends AppCompatActivity {
   private int mCount = 0;
   private TextView mShowCount;
   private int mColor;

   private SharedPreferences mPreferences;
   private String sharedPrefFile = 
      "com.example.android.hellosharedprefs";

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       mShowCount = (TextView) findViewById(R.id.textview);
       mColor = ContextCompat.getColor(this, 
          R.color.default_background);
       mPreferences = getSharedPreferences(
          sharedPrefFile, MODE_PRIVATE);

       // ...
    }
}

2.2 Save preferences in onPause()

Saving preferences is a lot like saving the instance state -- both operations set aside the data to a Bundle object as a key/value pair. For shared preferences, however, you save that data in the onPause() lifecycle callback, and you need a shared editor object (SharedPreferences.Editor) to write to the shared preferences object.

  1. Add the onPause() lifecycle method to MainActivity.
@Override
protected void onPause(){
   super.onPause();

   // ...
}
  1. In onPause(), get an editor for the SharedPreferences object:
SharedPreferences.Editor preferencesEditor = mPreferences.edit();

A shared preferences editor is required to write to the shared preferences object. Add this line to onPause() after the call to super.onPause().

  1. Use the putInt() method to put both the mCount and mColor integers into the shared preferences with the appropriate keys:
preferencesEditor.putInt(COUNT_KEY, mCount);
preferencesEditor.putInt(COLOR_KEY, mColor);

The SharedPreferences.Editor class includes multiple "put" methods for different data types, including putInt() and putString().

  1. Call apply() to save the preferences:
preferencesEditor.apply();

The apply() method saves the preferences asynchronously, off of the UI thread. The shared preferences editor also has a commit() method to synchronously save the preferences. The commit() method is discouraged as it can block other operations.

  1. Delete the entire onSaveInstanceState() method. Because the activity instance state contains the same data as the shared preferences, you can replace the instance state altogether.

Solution code for MainActivity onPause() method:

@Override
protected void onPause(){
   super.onPause();

   SharedPreferences.Editor preferencesEditor = mPreferences.edit();
   preferencesEditor.putInt(COUNT_KEY, mCount);
   preferencesEditor.putInt(COLOR_KEY, mColor);
   preferencesEditor.apply();
}

2.3 Restore preferences in onCreate()

As with the instance state, your app reads any saved shared preferences in the onCreate() method. Again, because the shared preferences contain the same data as the instance state, we can replace the state with the preferences here as well. Every time onCreate() is called -- when the app starts, on configuration changes -- the shared preferences are used to restore the state of the view.

  1. Locate the part of the onCreate() method that tests if the savedInstanceState argument is null and restores the instance state:
if (savedInstanceState != null) {
   mCount = savedInstanceState.getInt(COUNT_KEY);
   if (mCount != 0) {
       mShowCountTextView.setText(String.format("%s", mCount));
   }
   mColor = savedInstanceState.getInt(COLOR_KEY);
   mShowCountTextView.setBackgroundColor(mColor);
}
  1. Delete that entire block.
  2. In the onCreate() method, in the same spot where the instance state code was, get the count from the preferences with the COUNT_KEY key and assign it to the mCount variable.
mCount = mPreferences.getInt(COUNT_KEY, 0);

When you read data from the preferences you don't need to get a shared preferences editor. Use any of the "get" methods on a shared preferences object (such as getInt() or getString() to retrieve preference data.

Note that the getInt() method takes two arguments: one for the key, and the other for the default value if the key cannot be found. In this case the default value is 0, which is the same as the initial value of mCount.

  1. Update the value of the main TextView with the new count.
mShowCountTextView.setText(String.format("%s", mCount));
  1. Get the color from the preferences with the COLOR_KEY key and assign it to the mColor variable.
mColor = mPreferences.getInt(COLOR_KEY, mColor);

As before, the second argument to getInt() is the default value to use in case the key doesn't exist in the shared preferences. In this case you can just reuse the value of mColor, which was just initialized to the default background further up in the method.

  1. Update the background color of the main text view.
mShowCountTextView.setBackgroundColor(mColor);
  1. Run the app. Click the Count button and change the background color to update the instance state and the preferences.
  2. Rotate the device or emulator to verify that the count and color are saved across configuration changes.
  3. Force-quit the app using one of these methods:
  1. Re-run the app. The app restarts and loads the preferences, maintaining the state.

Solution code for MainActivity onCreate() method:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   // Initialize views, color, preferences
   mShowCountTextView = (TextView) findViewById(R.id.count_textview);
   mColor = ContextCompat.getColor(this, R.color.default_background);
   mPreferences = getSharedPreferences(
                         mSharedPrefFile, MODE_PRIVATE);

   // Restore preferences
   mCount = mPreferences.getInt(COUNT_KEY, 0);
   mShowCountTextView.setText(String.format("%s", mCount));
   mColor = mPreferences.getInt(COLOR_KEY, mColor);
   mShowCountTextView.setBackgroundColor(mColor);
}

2.4 Reset preferences in the reset() click handler

The reset button in the starter app resets both the count and color for the activity to their default values. Because the preferences hold the state of the activity, it's important to also clear the preferences at the same time.

  1. In the reset() onClick method, after the color and count are reset, get an editor for the SharedPreferences object:
SharedPreferences.Editor preferencesEditor = mPreferences.edit();
  1. Delete all the shared preferences:
preferencesEditor.clear();
  1. Apply the changes:
preferencesEditor.apply();

Solution code for the reset() method:

public void reset(View view) {
   // Reset count
   mCount = 0;
   mShowCountTextView.setText(String.format("%s", mCount));

   // Reset color
   mColor = ContextCompat.getColor(this, R.color.default_background);
   mShowCountTextView.setBackgroundColor(mColor);

   // Clear preferences
   SharedPreferences.Editor preferencesEditor = mPreferences.edit();
   preferencesEditor.clear();
   preferencesEditor.apply();

}

Android Studio project: HelloSharedPrefs

Challenge: Modify the HelloSharedPrefs app so that instead of automatically saving the state to the preferences file, add a second activity to change, reset, and save those preferences. Add a button to the app named Settings to launch that activity. Include toggle buttons and spinners to modify the preferences, and Save and Reset buttons for saving and clearing the preferences.

The related concept documentation is in 9.0: Data storage and 9.1: Shared preferences.

Android developer documentation:

Stack Overflow:

This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:

Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.

If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.

Build and run an app

Open the ScoreKeeper app that you created in the Android fundamentals 5.1: Drawables, styles, and themes lesson.

  1. Replace the saved instance state with shared preferences for each of the scores.
  2. To test the app, rotate the device to ensure that configuration changes read the saved preferences and update the UI.
  3. Stop the app and restart it to ensure that the preferences are saved.
  4. Add a Reset button that resets the score values to 0 and clears the shared preferences.

Answer these questions

Question 1

In which lifecycle method do you save the app state to shared preferences?

Question 2

In which lifecycle method do you restore the app state?

Question 3

Can you think of a case where it makes sense to have both shared preferences and instance state?

Submit your app for grading

Guidance for graders

Check that the app has the following features:

Make sure that the implementation of the on-click handler method for the Reset button does the following things:

To find the next practical codelab in the Android Developer Fundamentals (V2) course, see Codelabs for Android Developer Fundamentals (V2).

For an overview of the course, including links to the concept chapters, apps, and slides, see Android Developer Fundamentals (Version 2).