9.1: Shared Preferences

Contents:

Shared preferences allow you to read and write small amounts of primitive data as key/value pairs to a file on the device storage. The SharedPreference class provides APIs for getting a handle to a preference file and for reading, writing, and managing this data. The shared preferences file itself is managed by the framework and accessible to (shared with) all the components of your app. That data is not shared with or accessible to any other apps.

For managing large amounts of data, use a SQLite database or other suitable storage option, which will be discussed in a later chapter.

Shared preferences vs. saved instance state

In a previous chapter you learned about preserving state using saved instance states. Here is a comparison between the two.

Shared Preferences

Saved instance state

Persists across user sessions, even if your app is killed and restarted, or the device is rebooted.

Preserves state data across activity instances in the same user session.

Data that should be remembered across sessions, such as a user's preferred settings or their game score.

Data that should not be remembered across sessions, such as the currently selected tab, or any current state of an activity.

Small number of key/value pairs.

Small number of key/value pairs.

Data is private to the application.

Data is private to the application.

Common use is to store user preferences.

Common use is to recreate state after the device has been rotated.

Note: The SharedPreference APIs are also different from the Preference APIs. The Preference APIs can be used to build user interface for a settings page, and they do use shared preferences for their underlying implementation. See Settings for more information on settings and the Preference APIs.

Creating a shared preferences file

You need only one shared preferences file for your app, and it is customarily named with the package name of your app. This makes its name unique and easily associated with your app.

You create the shared preferences file in the onCreate() method of your main activity and store it in a member variable.

private String sharedPrefFile = "com.example.android.hellosharedprefs";
mPreferences = getSharedPreferences(sharedPrefFile, MODE_PRIVATE);

The mode argument is required, because older versions of Android had other modes that allowed you to create a world-readable or world-writable shared preferences file. These modes were deprecated in API 17, and are now strongly discouraged for security reasons. If you need to share data with other apps, use a service or a content provider.

Saving shared preferences

You save preferences in the onPause() state of the activity lifecycle using tge SharedPreferences.Editor interface.

  1. Get a SharedPreferences.Editor. The editor takes care of all the file operations for you. When two editors are modifying preferences at the same time, the last one to call apply wins.
  2. Add key/value pairs to the editor using the put method appropriate for the data type. The put methods will overwrite previously existing values of an existing key.
  3. Call apply() to write out your changes. 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. As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.

    You don't need to worry about Android component lifecycles and their interaction with apply() writing to disk. The framework makes sure in-flight disk writes from apply() complete before switching states.

@Override
protected void onPause() {
   super.onPause();
   SharedPreferences.Editor preferencesEditor = mPreferences.edit();
   preferencesEditor.putInt("count", mCount);
   preferencesEditor.putInt("color", mCurrentColor);
   preferencesEditor.apply();
}

Restoring shared preferences

You restore shared preferences in the onCreate() method of your activity. The get() methods take two arguments—one for the key and one for the default value if the key cannot be found. Using the default argument, you don't have to test whether the preference exists in the file.

mPreferences = getSharedPreferences(sharedPrefFile, MODE_PRIVATE);
if (savedInstanceState != null) {
    mCount = mPreferences.getInt("count", 1);
    mShowCount.setText(String.format("%s", mCount));

    mCurrentColor = mPreferences.getInt("color", mCurrentColor);
    mShowCount.setBackgroundColor(mCurrentColor);
} else { … }

Clearing shared preferences

To clear all the values in the shared preferences file, call the clear() method on the shared preferences editor and apply the changes.

SharedPreferences.Editor preferencesEditor = mPreferences.edit();
preferencesEditor.putInt("number", 42);
preferencesEditor.clear();
preferencesEditor.apply();

You can combine calls to put and clear. However, when applying the preferences, the clear is always done first, regardless of whether you called clear before or after the put methods on this editor.

Listening for preference changes

There are several reasons you might want to be notified as soon as the user changes one of the preferences. In order to receive a callback when a change happens to any one of the preferences, implement the SharedPreference.OnSharedPreferenceChangeListener interface and register the listener for the SharedPreferences object by calling registerOnSharedPreferenceChangeListener().

The interface has only one callback method, onSharedPreferenceChanged(), and you can implement the interface as a part of your activity.

public class SettingsActivity extends PreferenceActivity
                              implements OnSharedPreferenceChangeListener {
    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
    ...

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
        String key) {
        if (key.equals(KEY_PREF_SYNC_CONN)) {
            Preference connectionPref = findPreference(key);
            // Set summary to be the user-description for the selected value
            connectionPref.setSummary(sharedPreferences.getString(key, ""));
        }
    }
}

In this example, the method checks whether the changed setting is for a known preference key. It calls findPreference() to get the Preference object that was changed so it can modify the item's summary to be a description of the user's selection.

For proper lifecycle management in the activity, register and unregister your SharedPreferences.OnSharedPreferenceChangeListener during the onResume() and onPause() callbacks, respectively:

@Override
protected void onResume() {
    super.onResume();
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

Hold a reference to the listener

When you call registerOnSharedPreferenceChangeListener(), the preference manager does not currently store a reference to the listener. You must hold onto a reference to the listener, or it will be susceptible to garbage collection. Keep a reference to the listener in the instance data of an object that will exist as long as you need the listener.

SharedPreferences.OnSharedPreferenceChangeListener listener =
    new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // listener implementation
  }
};
prefs.registerOnSharedPreferenceChangeListener(listener);

The related exercises and practical documentation is in Android Developer Fundamentals: Practicals.

Learn more

Stackoverflow

results matching ""

    No results matching ""