Back to Posts

Working with SharedPreferences in Flutter: Complete Guide

5 min read
<div style="text-align: center;"> <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDMwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPCEtLSBTaGFyZWRQcmVmZXJlbmNlcyBleGFtcGxlIC0tPgogIDxyZWN0IHdpZHRoPSIzMDAiIGhlaWdodD0iMjAwIiBmaWxsPSIjRkZGIiBzdHJva2U9IiMwMDAiLz4KICA8dGV4dCB4PSIxNTAiIHk9IjEwMCIgZm9udC1mYW1pbHk9IkFyaWFsIiBmb250LXNpemU9IjEyIiBmaWxsPSIjMjEyMTIxIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5TaGFyZWRQcmVmZXJlbmNlczwvdGV4dD4KPC9zdmc+" alt="SharedPreferences Example" width="300" /> </div>

SharedPreferences is a simple key-value storage system in Flutter that allows you to persist small amounts of data locally. This guide will show you how to effectively use SharedPreferences in your Flutter applications.

Getting Started

1. Add Dependency

Add the shared_preferences package to your pubspec.yaml:

dependencies:
  shared_preferences: ^2.2.2

2. Basic Implementation

import 'package:shared_preferences/shared_preferences.dart';

class SharedPreferencesService {
  static SharedPreferences? _prefs;
  static Future<SharedPreferences> get prefs async {
    _prefs ??= await SharedPreferences.getInstance();
    return _prefs!;
  }

  // Save string
  static Future<bool> saveString(String key, String value) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.setString(key, value);
  }

  // Get string
  static Future<String?> getString(String key) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.getString(key);
  }

  // Remove value
  static Future<bool> remove(String key) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.remove(key);
  }

  // Clear all
  static Future<bool> clear() async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.clear();
  }
}

Advanced Usage

1. Working with Different Data Types

class SharedPreferencesService {
  // Save integer
  static Future<bool> saveInt(String key, int value) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.setInt(key, value);
  }

  // Save boolean
  static Future<bool> saveBool(String key, bool value) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.setBool(key, value);
  }

  // Save double
  static Future<bool> saveDouble(String key, double value) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.setDouble(key, value);
  }

  // Save string list
  static Future<bool> saveStringList(String key, List<String> value) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.setStringList(key, value);
  }
}

2. Complex Data Storage

class UserPreferences {
  static const String _userKey = 'user_data';

  static Future<bool> saveUser(User user) async {
    final prefs = await SharedPreferencesService.prefs;
    return prefs.setString(_userKey, json.encode(user.toJson()));
  }

  static Future<User?> getUser() async {
    final prefs = await SharedPreferencesService.prefs;
    final userJson = prefs.getString(_userKey);
    if (userJson == null) return null;
    return User.fromJson(json.decode(userJson));
  }
}

class User {
  final String name;
  final String email;
  final int age;

  User({required this.name, required this.email, required this.age});

  Map<String, dynamic> toJson() => {
    'name': name,
    'email': email,
    'age': age,
  };

  factory User.fromJson(Map<String, dynamic> json) => User(
    name: json['name'],
    email: json['email'],
    age: json['age'],
  );
}

3. Settings Management

class AppSettings {
  static const String _themeKey = 'theme_mode';
  static const String _languageKey = 'language';
  static const String _notificationsKey = 'notifications_enabled';

  static Future<bool> setThemeMode(bool isDark) async {
    return SharedPreferencesService.saveBool(_themeKey, isDark);
  }

  static Future<bool> getThemeMode() async {
    return SharedPreferencesService.getBool(_themeKey) ?? false;
  }

  static Future<bool> setLanguage(String languageCode) async {
    return SharedPreferencesService.saveString(_languageKey, languageCode);
  }

  static Future<String> getLanguage() async {
    return SharedPreferencesService.getString(_languageKey) ?? 'en';
  }

  static Future<bool> setNotificationsEnabled(bool enabled) async {
    return SharedPreferencesService.saveBool(_notificationsKey, enabled);
  }

  static Future<bool> getNotificationsEnabled() async {
    return SharedPreferencesService.getBool(_notificationsKey) ?? true;
  }
}

Best Practices

  1. Data Management

    • Use meaningful keys
    • Implement proper error handling
    • Handle null values
    • Use type-safe methods
  2. Performance

    • Minimize read/write operations
    • Batch operations when possible
    • Use appropriate data types
    • Implement proper cleanup
  3. Security

    • Don't store sensitive data
    • Use encryption for sensitive data
    • Implement proper data validation
    • Handle data migration
  4. Code Organization

    • Create service classes
    • Use constants for keys
    • Implement proper error handling
    • Follow naming conventions

Common Issues and Solutions

  1. Null Safety

    // Handle null values properly
    final value = await SharedPreferencesService.getString('key') ?? 'default';
  2. Data Migration

    // Handle data migration
    static Future<void> migrateData() async {
      final prefs = await SharedPreferencesService.prefs;
      final oldValue = prefs.getString('old_key');
      if (oldValue != null) {
        await prefs.setString('new_key', oldValue);
        await prefs.remove('old_key');
      }
    }
  3. Error Handling

    // Implement proper error handling
    try {
      await SharedPreferencesService.saveString('key', 'value');
    } catch (e) {
      // Handle error
      print('Error saving data: $e');
    }

Conclusion

SharedPreferences is a powerful tool for local data storage in Flutter applications. Remember to:

  • Use appropriate data types
  • Implement proper error handling
  • Follow best practices
  • Consider security implications

Happy coding!