Flutter’s Shared Preferences: A Lightweight Local Storage Solution

Flutter’s Shared Preferences: A Lightweight Local Storage Solution

Shared preferences in Flutter are a simple and lightweight way to persistently store small amounts of data, such as user preferences or app settings. Unlike databases, shared preferences don’t require a complex setup and are ideal for scenarios where you need to store key-value pairs.

Let’s take a step-by-step approach to implementing shared preferences in a Flutter application.

Start by adding the shared_preferences package to your pubspec.yaml file. You can find the latest version on pub.dev.

dependencies:
  shared_preferences: <letest_version>

Run flutter pub get to fetch and install the package.

In your Dart file, import the shared_preferences package.

import 'package:shared_preferences/shared_preferences.dart';

Before using shared preferences, initialize them in the main() function or the initState() method.

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Initialize shared preferences
    SharedPreferences.getInstance().then((prefs) {
      runApp(
        MaterialApp(
          home: MyHomePage(prefs),
        ),
      );
    });
  }
}

Now, you can easily use shared preferences to store and retrieve data.

class MyHomePage extends StatefulWidget {
  final SharedPreferences prefs;

  MyHomePage(this.prefs);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _username = "";

  @override
  void initState() {
    super.initState();
    // Retrieve data from shared preferences
    _username = widget.prefs.getString('username') ?? "";
  }

  void _saveUsername(String username) {
    // Save data to shared preferences
    widget.prefs.setString('username', username);
    setState(() {
      _username = username;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Shared Preferences in Flutter'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Welcome, $_username!'),
            TextField(
              onChanged: (value) => _saveUsername(value),
              decoration: InputDecoration(labelText: 'Enter your username'),
            ),
          ],
        ),
      ),
    );
  }
}

Singleton Method:

The Singleton pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to it. This single instance is responsible for controlling actions and coordinating tasks across the entire application.

Use Cases:

  1. Managing Shared Resources:
    • Singletons are excellent for managing resources that need to be shared across different parts of an application. For example, when dealing with a database connection, network requests, or shared preferences, a singleton ensures that there’s only one instance, preventing unnecessary resource duplication and enhancing efficiency.
  2. Global State Management:
    • Flutter applications often require a centralized state management solution. Singletons can serve as a global store for application state, providing easy access to critical data and ensuring consistency across different screens or widgets.
  3. Configuration Settings:
    • Use singletons to handle application configuration settings. For instance, managing themes, language preferences, or any other configuration that needs to be accessible and consistent throughout the app.
  4. Service Locators:
    • Singleton pattern can be employed as a service locator, where a single instance manages the registration and retrieval of various services within the application. This promotes modularity and helps in organizing dependencies efficiently.

Benefits:

  1. Memory Efficiency:
    • Singletons help in conserving memory by ensuring that only one instance of the class is created and shared across the application. This is particularly beneficial when dealing with resource-intensive operations.
  2. Global Accessibility:
    • Singletons provide a centralized point of access to shared resources, reducing the need for passing instances between different parts of the application. This simplifies code and enhances maintainability.
  3. Consistent State:
    • With a singleton managing the state, you can ensure a consistent application state throughout its lifecycle. This is especially valuable when dealing with complex state management scenarios in Flutter.
  4. Easy Initialization and Cleanup:
    • Singletons can encapsulate initialization logic, making it easy to manage the lifecycle of shared resources. Additionally, cleanup tasks can be efficiently handled within the singleton instance.

Implementation Example:

Here’s a basic example of implementing a singleton in Dart:

class MySingleton {
  static MySingleton _instance;

  // Private constructor to prevent instantiation
  MySingleton._();

  // Getter to access the instance
  static MySingleton get instance {
    if (_instance == null) {
      _instance = MySingleton._();
    }
    return _instance;
  }

  // Your singleton methods and properties go here
  // ...
}

Implement SharedPreferences as a Singleton:

To use shared preferences as a singleton in Flutter, you can create a dedicated class that manages the shared preferences instance and ensures there’s only one instance throughout the application. Here’s an example of how you can implement a Singleton for shared preferences:

import 'package:shared_preferences/shared_preferences.dart';

class LocalPreferences {
  static LocalPreferences? _instance;
  static late SharedPreferences _prefs;

  // Private constructor to prevent instantiation
  LocalPreferences._();

  // Public factory method to get the instance
  factory LocalPreferences() {
    _instance ??= LocalPreferences._();
    return _instance!;
  }

  // Initialize SharedPreferences
  Future<void> init() async {
    _prefs = await SharedPreferences.getInstance();
  }

  // Methods for reading and writing data

  static String getString(String key, {String defaultValue = ''}) {
    return _prefs.getString(key) ?? defaultValue;
  }

  static Future<bool> setString(String key, String value) {
    return _prefs.setString(key, value);
  }

  static int getInt(String key, {int defaultValue = 0}) {
    return _prefs.getInt(key) ?? defaultValue;
  }

  static Future<bool> setInt(String key, int value) {
    return _prefs.setInt(key, value);
  }

  static double getDouble(String key, {double defaultValue = 0.0}) {
    return _prefs.getDouble(key) ?? defaultValue;
  }

  static Future<bool> setDouble(String key, double value) {
    return _prefs.setDouble(key, value);
  }

  static bool getBool(String key, {bool defaultValue = false}) {
    return _prefs.getBool(key) ?? defaultValue;
  }

  static Future<bool> setBool(String key, bool value) {
    return _prefs.setBool(key, value);
  }

  // Add other methods as needed

  // Clear all data in SharedPreferences
  static Future<void> clear() async {
    await _prefs.clear();
  }
}

Add this two lines of code inside void main() function:

WidgetsFlutterBinding.ensureInitialized();
await LocalPreferences().init();

Congratulation now you can use SharedPreferences in your whole application without making any new instance.

Thanks for reading. Stay with us for more programming knowledge.
Happy coding……

2 Comments

Leave a Reply

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