Persisting Key-Value Data in Android with SharedPreferences
Overview
SharedPreferences is Android's simplest key-value storage mechanism. It allows you to store small amounts of primitive data (such as integers, booleans, or strings) in an XML file that persists across app restarts.
Basic Usage
To use SharedPreferences, follow three steps:
- Obtain a
SharedPreferencesinstance viagetSharedPreferences()orgetPreferences(). - Get an
Editorfrom that instance to modify values. - Commit or apply changes using
commit()(synchronous) orapply()(asynchronous).
Example 1: Using getPreferences()
The getPreferences() method (single parameter) creates a preferences file named after the current activity.
// MainActivity.java
package com.example.sharedpreferences;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get activity-specific preferences file
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
// Store a key-value pair
editor.putInt("MY_NUMBER", 100);
editor.apply(); // asynchronous commit
// Retrieve the stored value (default 0)
int storedValue = prefs.getInt("MY_NUMBER", 0);
Log.d("mylog", "Stored value: " + storedValue);
}
}
After running, an XML file named after the activity (e.g., MainActivity.xml) is created in the device's internal storage:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<int name="MY_NUMBER" value="100" />
</map>
Example 2: Using getSharedPreferences()
The two-parameter variant allows you to define a custom file name, which is useful for sharing data across multiple activities.
// MainActivity.java (partial)
SharedPreferences customPrefs = getSharedPreferences("MY_data", Context.MODE_PRIVATE);
SharedPreferences.Editor editor2 = customPrefs.edit();
editor2.putInt("NUMBER", 600);
editor2.apply();
int retrieved = customPrefs.getInt("NUMBER", 0);
Log.d("mylog", "Custom pref value: " + retrieved);
This creates an XML file named MY_data.xml.
Ancapsulating with a Dedicated Data Class
To keep your code organized, you can wrap the SharedPreferences logic in a seperate helper class.
// MyData.java
package com.example.sharedpreferences;
import android.content.Context;
import android.content.SharedPreferences;
public class MyData {
public int number;
private Context mContext;
public MyData(Context context) {
// Use application context to avoid memory leaks
mContext = context.getApplicationContext();
}
public void save() {
String fileName = mContext.getResources().getString(R.string.MY_data);
SharedPreferences prefs = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
String key = mContext.getResources().getString(R.string.MY_KEY);
editor.putInt(key, number);
editor.apply();
}
public int load() {
String fileName = mContext.getResources().getString(R.string.MY_data);
SharedPreferences prefs = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
String key = mContext.getResources().getString(R.string.MY_KEY);
int defaultValue = mContext.getResources().getInteger(R.integer.defValue);
number = prefs.getInt(key, defaultValue);
return number;
}
}
Then, in your activity, use this class rather than directly manipulating the preferences file.
// MainActivity.java (using MyData)
MyData myData = new MyData(getApplicationContext());
myData.number = 1000;
myData.save();
int loadedValue = myData.load();
Log.d("mylog", "Loaded value: " + loadedValue);
Using Resource Values for Flexibility
Define keys, file names, and default values in Android resource files to keep them maintainable.
// res/values/strings.xml
<resources>
<string name="app_name">SharedPreferences</string>
<string name="MY_data">my_data</string>
<string name="MY_KEY">my_key</string>
</resources>
// res/values/integers.xml
<resources>
<integer name="defValue">0</integer>
</resources>
This approach centralizes configuration and makes future changes easier.