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……

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

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