Using the shared_preferences Package for Simple Key-Value Storage in Flutter

In Flutter development, managing and persisting simple data like user preferences, settings, or application state is crucial for creating a smooth and personalized user experience. The shared_preferences package provides a simple way to store and retrieve key-value pairs locally on a user’s device. This article delves into using the shared_preferences package effectively in Flutter applications.

What is shared_preferences?

The shared_preferences plugin is a Flutter package that offers a persistent store for simple data. It is typically used to store data such as:

  • User preferences (e.g., theme settings, notification preferences)
  • Application settings (e.g., API endpoints, default values)
  • Simple application state (e.g., whether the user has seen a tutorial)

Why Use shared_preferences?

  • Ease of Use: Provides a straightforward API for reading and writing data.
  • Persistence: Data remains stored even after the app is closed.
  • Simple Data Storage: Suitable for small amounts of data that don’t require a database.

How to Use shared_preferences in Flutter

To start using shared_preferences, follow these steps:

Step 1: Add the Dependency

Add the shared_preferences package to your pubspec.yaml file:

dependencies:
  shared_preferences: ^2.2.2

Then, run flutter pub get to install the package.

Step 2: Import the Package

In your Dart file, import the shared_preferences package:

import 'package:shared_preferences/shared_preferences.dart';

Step 3: Store Data

You can store data using various methods provided by the SharedPreferences class. Here’s how to store different types of data:

import 'package:shared_preferences/shared_preferences.dart';

Future saveData() async {
  final prefs = await SharedPreferences.getInstance();
  
  prefs.setInt('counter', 42);           // Stores an integer
  prefs.setDouble('pi', 3.14159);         // Stores a double
  prefs.setBool('isDarkMode', true);       // Stores a boolean
  prefs.setString('userName', 'John Doe'); // Stores a string
  prefs.setStringList('myList', ['item1', 'item2', 'item3']); // Stores a list of strings
}

Step 4: Retrieve Data

You can retrieve stored data using the corresponding get methods:

import 'package:shared_preferences/shared_preferences.dart';

Future loadData() async {
  final prefs = await SharedPreferences.getInstance();

  final counter = prefs.getInt('counter') ?? 0;          // Retrieve an integer, default to 0 if null
  final pi = prefs.getDouble('pi') ?? 0.0;              // Retrieve a double, default to 0.0 if null
  final isDarkMode = prefs.getBool('isDarkMode') ?? false;   // Retrieve a boolean, default to false if null
  final userName = prefs.getString('userName') ?? '';     // Retrieve a string, default to '' if null
  final myList = prefs.getStringList('myList') ?? [];    // Retrieve a list of strings, default to [] if null

  print('Counter: $counter');
  print('Pi: $pi');
  print('Is Dark Mode: $isDarkMode');
  print('User Name: $userName');
  print('My List: $myList');
}

Step 5: Remove Data

You can remove individual keys or clear all data:

import 'package:shared_preferences/shared_preferences.dart';

Future removeData() async {
  final prefs = await SharedPreferences.getInstance();
  
  // Remove a single key
  await prefs.remove('userName');
  
  // Clear all data
  await prefs.clear();
}

Example: Storing and Retrieving Theme Preferences

Let’s create a simple example where we store and retrieve theme preferences (dark or light mode).

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State {
  bool _isDarkMode = false;

  @override
  void initState() {
    super.initState();
    _loadThemePreference();
  }

  // Load the theme preference from SharedPreferences
  Future _loadThemePreference() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      _isDarkMode = prefs.getBool('isDarkMode') ?? false;
    });
  }

  // Save the theme preference to SharedPreferences
  Future _saveThemePreference(bool value) async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      _isDarkMode = value;
    });
    await prefs.setBool('isDarkMode', value);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Shared Preferences Example',
      theme: ThemeData(
        brightness: _isDarkMode ? Brightness.dark : Brightness.light,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Theme Preference'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Dark Mode: ${_isDarkMode ? 'On' : 'Off'}',
                style: TextStyle(fontSize: 20),
              ),
              Switch(
                value: _isDarkMode,
                onChanged: (value) {
                  _saveThemePreference(value);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

In this example:

  • We load the theme preference in initState.
  • We save the theme preference whenever the switch changes.
  • The UI updates based on the stored preference.

Best Practices

  • Use Async/Await: Always use async and await when working with SharedPreferences to avoid blocking the UI thread.
  • Handle Errors: Implement error handling to gracefully manage any issues during data storage or retrieval.
  • Data Size: Avoid storing large amounts of data in SharedPreferences. It is designed for simple key-value storage, not as a database replacement.
  • Security: Be mindful of the data you store. Sensitive data should be encrypted or stored more securely.

Conclusion

The shared_preferences package is a handy tool for Flutter developers to manage and persist simple key-value data locally. It’s perfect for storing user preferences and small application settings. By following the guidelines and best practices outlined in this article, you can effectively use shared_preferences to enhance the user experience in your Flutter apps.