In Flutter, understanding design patterns is crucial for building scalable and maintainable applications. One such design pattern that often proves useful is the Singleton in Flutter.
What is a Singleton?
The Singleton in Flutter is a design pattern that ensures a class has only one instance and provides a global point to this instance.
Implementing a Singleton in Dart
In Dart, Singleton is a class that has its own instance and ensures that no other instances can be created of that class.
Here’s a basic example of a Singleton in Dart:
1 2 3 4 5 |
class NetworkManager { NetworkManager._privateConstructor(); static final NetworkManager _instance = NetworkManager._privateConstructor(); static NetworkManager get instance => _instance; } |
In this example, the _privarConstructor is a private constructor that prevents direct instantiation of the
NetworkManager class from outside. Moreover, the _instance variable holds the single instance of the class, and the instance getter provides access to it.
You may also check our Flutter app development page.
Using Singleton in Flutter
Now we understand how to create a Singleton in Dart, we can implement the singleton class for various purposes stated below.
You can check the official documentation here.
1. Managing Global State
For a centralized state management system, Singleton can be an excellent. In addition, Singletons can be used to manage the global state.
1 2 3 4 5 6 |
class AppState { AppState._privateConstructor(); static final AppState _instance = AppState._privateConstructor(); static AppState get instance => _instance; String username = 'Mobikul'; } |
In this example, AppState is a Singleton class responsible for managing the global state of the application. Developers can access and modify the state from anywhere in the application using AppState.instance
2. Network Requests
Creating a single instance to manage API calls ensures efficient resource utilization.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import 'package:http/http.dart' as http; class NetworkManager { NetworkManager._privateConstructor(); static final NetworkManager _instance = NetworkManager._privateConstructor(); static NetworkManager get instance => _instance; final String baseUrl = 'https://mobikul.com'; Future<http.Response> makeRequest(String endpoint) async { final response = await http.get(Uri.parse('$baseUrl/$endpoint')); return response; } } |
We can use NetworkManager.instance.makeRequest(‘endpoint’) to make network calls throughout the application.
3. Navigation Management
We can use Singleton for handling the routing and navigation logic in the application.
1 2 3 4 5 6 7 8 9 10 11 |
import 'package:flutter/material.dart'; class NavigationManager { NavigationManager._privateConstructor(); static final NavigationManager _instance = NavigationManager._privateConstructor(); static NavigationManager get instance => _instance; final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); void pushNamed(String routeName) { navigatorKey.currentState?.pushNamed(routeName); } } |
Here, we are using the navigatorKey to access the navigator state and the pushNamed method simplifies the process of navigating to named routes.
Limitations of Singleton
1. Memory Management
We need to be more cautious that resources held by Singletons are appropriately released when they are no longer needed.
2. Thread Safety
If the application involves multiple isolates or threads, ensure that your Singleton implementation is thread-safe to avoid potential race conditions.
Conclusion
By understanding the principles behind the Singleton pattern and its application in Dart and Flutter, we can create more maintainable and scalable Flutter applications.
Please check my other blogs here.