When working with Flutter, you may encounter an error message that says “The ‘instance’ getter on the ServicesBinding binding mixin is only available once that binding has been initialized”. This error can occur when using packages like Shared Preferences that rely on the Flutter framework’s ServicesBinding to function correctly.
Why Does the ServicesBinding Error Occur?
To demonstrate why the error occurs we have the below code snippet.
import 'package:shared_preferences/shared_preferences.dart';
Future<void> main() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setString('key', 'value');
}
In this code, snippet we import the Shared Preferences package and try to retrieve an instance of the SharedPreferences class and assign it to the preferences
variable. The main is asynchronous because the getInstance
function returns a Future
. At last, we are trying to save a new String inside the shared preferences.
However, when running the code we will encounter the “ServicesBinding binding mixin is only available once” error. This happens because, in Flutter, the ServiceBinding
is responsible for initializing and managing various framework services.
The Shared Preferences package relies on the ServiceBinding
to initialize the shared preferences service before it can be used. Normally the initialization in Flutter applications happens when we call the runApp
function.
void runApp(Widget app) {
final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
assert(binding.debugCheckZone('runApp'));
binding
..scheduleAttachRootWidget(binding.wrapWithDefaultView(app))
..scheduleWarmUpFrame();
}
However, sometimes you want to perform actions before you call the runApp
function. Therefore let us have a look at the following section where we go over the solution.
Solve the ServicesBinding Error
The previous section might already have spoiled the solution for the “ServicesBinding binding mixin is only available once” error, but instead of waiting for the runApp
function to call the WidgetsFlutterBinding.ensureInitialized
function. We want to call it ourselves.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setString('key', 'value');
}
In this updated code snippet, we call the WidgetsFlutterBinding.ensureInitialized
function to ensure that Flutter’s ServiceBinding
is ready. After that, we can use the SharedPreferences
class without running into any problems.
In test cases you can use
TestWidgetsFlutterBinding.ensureInitialized
. This function will use a fake http client that always returns a status code of 400. This is to prevent tests from making actual network calls.
Conclusion
In Flutter, it is important to ensure that the framework’s ServiceBinding
is ready before running your code. This includes packages that rely on how Flutter works internally. By using the WidgetsFlutterBinding.ensureInitialized
function, you can prevent running into ServiceBinding
related errors.