BLOG POSTS
Android Shared Preferences – Example Tutorial

Android Shared Preferences – Example Tutorial

Android Shared Preferences is a persistent storage mechanism that allows developers to store and retrieve small amounts of primitive data as key-value pairs in Android applications. This lightweight data storage solution is essential for maintaining user settings, app configuration, login states, and other simple data that needs to survive app restarts and device reboots. This tutorial will walk you through implementing Shared Preferences from basic usage to advanced techniques, common pitfalls to avoid, and performance considerations for production applications.

How Android Shared Preferences Works

Shared Preferences stores data in XML files within your app’s private storage directory. The Android system handles the underlying file operations, providing a simple interface for developers to work with key-value pairs. Each preference file is associated with a specific context and can be accessed in different modes:

  • MODE_PRIVATE: Default mode where files are accessible only to your app
  • MODE_WORLD_READABLE: Deprecated in API 17, allowed other apps to read
  • MODE_WORLD_WRITEABLE: Deprecated in API 17, allowed other apps to write
  • MODE_MULTI_PROCESS: Deprecated in API 23, handled multi-process access

The preference files are stored in /data/data/your.package.name/shared_prefs/ and are automatically backed up by Android’s Auto Backup feature unless explicitly excluded.

Step-by-Step Implementation Guide

Basic Setup and Writing Data

Here’s how to create and write to Shared Preferences:

// Get SharedPreferences instance
SharedPreferences sharedPreferences = getSharedPreferences("MyAppPrefs", Context.MODE_PRIVATE);

// Get SharedPreferences Editor
SharedPreferences.Editor editor = sharedPreferences.edit();

// Store different data types
editor.putString("username", "john_doe");
editor.putInt("user_age", 25);
editor.putBoolean("is_logged_in", true);
editor.putFloat("app_rating", 4.5f);
editor.putLong("last_login_time", System.currentTimeMillis());

// Commit changes synchronously (blocks UI thread)
editor.commit();

// Or apply changes asynchronously (recommended)
editor.apply();

Reading Data from Shared Preferences

// Reading stored values with default fallbacks
SharedPreferences sharedPreferences = getSharedPreferences("MyAppPrefs", Context.MODE_PRIVATE);

String username = sharedPreferences.getString("username", "guest");
int userAge = sharedPreferences.getInt("user_age", 0);
boolean isLoggedIn = sharedPreferences.getBoolean("is_logged_in", false);
float appRating = sharedPreferences.getFloat("app_rating", 0.0f);
long lastLoginTime = sharedPreferences.getLong("last_login_time", 0L);

// Check if key exists
if (sharedPreferences.contains("username")) {
    // Key exists, proceed with logic
}

Advanced Operations

// Remove specific key
editor.remove("username");
editor.apply();

// Clear all preferences
editor.clear();
editor.apply();

// Get all preferences as Map
Map<String, ?> allPrefs = sharedPreferences.getAll();
for (Map.Entry<String, ?> entry : allPrefs.entrySet()) {
    Log.d("Preferences", entry.getKey() + ": " + entry.getValue().toString());
}

// Listen for preference changes
SharedPreferences.OnSharedPreferenceChangeListener listener = 
    new SharedPreferences.OnSharedPreferenceChangeListener() {
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals("username")) {
            // Handle username change
            String newUsername = sharedPreferences.getString(key, "");
            updateUI(newUsername);
        }
    }
};

// Register and unregister listener
sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
// Don't forget to unregister in onDestroy()
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);

Real-World Examples and Use Cases

User Settings Management

public class SettingsManager {
    private static final String PREF_NAME = "app_settings";
    private static final String KEY_THEME = "selected_theme";
    private static final String KEY_NOTIFICATIONS = "notifications_enabled";
    private static final String KEY_LANGUAGE = "app_language";
    
    private SharedPreferences prefs;
    private SharedPreferences.Editor editor;
    
    public SettingsManager(Context context) {
        prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
        editor = prefs.edit();
    }
    
    public void setTheme(String theme) {
        editor.putString(KEY_THEME, theme);
        editor.apply();
    }
    
    public String getTheme() {
        return prefs.getString(KEY_THEME, "light");
    }
    
    public void setNotificationsEnabled(boolean enabled) {
        editor.putBoolean(KEY_NOTIFICATIONS, enabled);
        editor.apply();
    }
    
    public boolean areNotificationsEnabled() {
        return prefs.getBoolean(KEY_NOTIFICATIONS, true);
    }
}

Session Management

public class SessionManager {
    private static final String PREF_NAME = "user_session";
    private static final String KEY_IS_LOGGED_IN = "is_logged_in";
    private static final String KEY_USER_ID = "user_id";
    private static final String KEY_AUTH_TOKEN = "auth_token";
    private static final String KEY_LOGIN_TIME = "login_time";
    
    private SharedPreferences prefs;
    private SharedPreferences.Editor editor;
    
    public SessionManager(Context context) {
        prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
        editor = prefs.edit();
    }
    
    public void createLoginSession(String userId, String authToken) {
        editor.putBoolean(KEY_IS_LOGGED_IN, true);
        editor.putString(KEY_USER_ID, userId);
        editor.putString(KEY_AUTH_TOKEN, authToken);
        editor.putLong(KEY_LOGIN_TIME, System.currentTimeMillis());
        editor.apply();
    }
    
    public boolean isLoggedIn() {
        return prefs.getBoolean(KEY_IS_LOGGED_IN, false);
    }
    
    public void logout() {
        editor.clear();
        editor.apply();
    }
    
    public boolean isSessionExpired() {
        long loginTime = prefs.getLong(KEY_LOGIN_TIME, 0);
        long currentTime = System.currentTimeMillis();
        long sessionDuration = 24 * 60 * 60 * 1000; // 24 hours
        
        return (currentTime - loginTime) > sessionDuration;
    }
}

Comparisons with Alternative Storage Solutions

Storage Method Use Case Performance Data Size Limit Complexity Backup Support
Shared Preferences Simple key-value pairs, settings Fast for small data ~1MB recommended Low Yes (Auto Backup)
SQLite Database Complex relational data Good for large datasets 128TB theoretical High Manual implementation
Internal Files Private app files, caching Good for large files Available storage Medium Configurable
Room Database Structured data with relationships Optimized SQLite wrapper 128TB theoretical Medium Manual implementation

Best Practices and Performance Considerations

Performance Optimization

  • Use apply() instead of commit(): apply() is asynchronous and doesn’t block the UI thread
  • Batch operations: Group multiple preference changes in a single editor session
  • Avoid storing large data: Keep individual values under 1KB for optimal performance
  • Cache frequently accessed values: Store commonly used preferences in memory
// Good: Batch operations
SharedPreferences.Editor editor = prefs.edit();
editor.putString("key1", "value1");
editor.putString("key2", "value2");
editor.putString("key3", "value3");
editor.apply(); // Single write operation

// Bad: Multiple separate operations
prefs.edit().putString("key1", "value1").apply();
prefs.edit().putString("key2", "value2").apply();
prefs.edit().putString("key3", "value3").apply();

Security Considerations

For sensitive data that requires additional security when deploying on VPS or dedicated servers for backend integration:

// Use EncryptedSharedPreferences for sensitive data (API 23+)
MasterKeys.AliasSpec spec = MasterKeys.AliasSpec.Builder(MasterKeys.AES256_GCM_SPEC)
    .setKeyScheme(MasterKeys.KeyScheme.AES256_GCM)
    .build();

String masterKeyAlias = MasterKeys.getOrCreate(spec);

EncryptedSharedPreferences encryptedPrefs = EncryptedSharedPreferences.create(
    "encrypted_prefs",
    masterKeyAlias,
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);

// Use like regular SharedPreferences
encryptedPrefs.edit().putString("secure_token", "sensitive_data").apply();

Common Pitfalls and Troubleshooting

Memory Leaks with Listeners

public class MainActivity extends AppCompatActivity {
    private SharedPreferences.OnSharedPreferenceChangeListener listener;
    private SharedPreferences prefs;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        prefs = getSharedPreferences("MyPrefs", MODE_PRIVATE);
        
        // Create listener
        listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
            @Override
            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                // Handle changes
            }
        };
        
        // Register listener
        prefs.registerOnSharedPreferenceChangeListener(listener);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // IMPORTANT: Unregister to prevent memory leaks
        if (prefs != null && listener != null) {
            prefs.unregisterOnSharedPreferenceChangeListener(listener);
        }
    }
}

commit() vs apply() Issues

  • commit() blocks the UI thread: Can cause ANR (Application Not Responding) errors
  • commit() returns boolean: Indicates success/failure, useful for critical operations
  • apply() is asynchronous: Better for UI performance but doesn’t provide feedback
// Use commit() only when you need the return value
if (editor.commit()) {
    Log.d("Prefs", "Successfully saved preferences");
    proceedWithCriticalOperation();
} else {
    Log.e("Prefs", "Failed to save preferences");
    handleSaveError();
}

// Use apply() for most cases
editor.apply(); // Fire and forget

Handling Large Data Sets

SharedPreferences loads the entire XML file into memory on first access. For large datasets, consider alternatives:

// Bad: Storing large JSON strings
editor.putString("large_json_data", hugJsonString); // Slows down app startup

// Better: Use SQLite or Room for large structured data
// Or split into smaller preference files
SharedPreferences userPrefs = getSharedPreferences("user_data", MODE_PRIVATE);
SharedPreferences appPrefs = getSharedPreferences("app_settings", MODE_PRIVATE);
SharedPreferences cachePrefs = getSharedPreferences("cache_data", MODE_PRIVATE);

Integration with Modern Architecture Components

Using SharedPreferences with LiveData and ViewModel:

public class PreferenceRepository {
    private SharedPreferences prefs;
    private MutableLiveData<String> usernameLiveData = new MutableLiveData<>();
    
    public PreferenceRepository(Context context) {
        prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
        
        prefs.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> {
            if ("username".equals(key)) {
                usernameLiveData.setValue(sharedPreferences.getString(key, ""));
            }
        });
        
        // Initialize with current value
        usernameLiveData.setValue(prefs.getString("username", ""));
    }
    
    public LiveData<String> getUsername() {
        return usernameLiveData;
    }
    
    public void setUsername(String username) {
        prefs.edit().putString("username", username).apply();
    }
}

For comprehensive Android development and testing, consider the official Android Shared Preferences documentation and SharedPreferences API reference for the latest updates and additional methods.

SharedPreferences remains one of the most reliable and efficient ways to handle simple data persistence in Android applications. When implemented correctly with proper error handling and performance considerations, it provides a robust foundation for app configuration and user preference management.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked