The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
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. In this post, we will go over a code example that uses shared_preferences to understand why this error happens and how to fix it.
Error example
The purpose of the code below is to demonstrate how the error can occur:
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 in the main
function. We make the function asynchronous because getInstance
returns a Future
. Finally, we attempt to add a new entry to the shared preferences.
However, when running the code, we encounter the error message The 'instance' getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
This occurs because in Flutter, the ServicesBinding
is responsible for initializing and managing various framework services like accessibility and gestures.
The SharedPreferences
package relies on the ServicesBinding
to initialize the shared preferences service before it can be used. Normally, the initialization happens when we call the runApp
function.
void runApp(Widget app) {
final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
...
}
But in our code, we did not call it, and if we need some functionality before calling the runApp
function, we need a different approach.
Solution
So the proper solution to fixing the error is to use WidgetsFlutterBinding.ensureInitialized
function, which guarantees that the necessary parts of Flutter are set up before we run our code, see the code below:
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, we call WidgetsFlutterBinding.ensureInitialized
function to make sure Flutter is ready. This way, we can safely use the SharedPreferences
class without getting the previous error.
Now we no longer run into the The 'instance' getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
error.
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 network calls, which could introduce flakiness.
Conclusion
In Flutter, it is important to make sure everything is ready before running your code. This includes packages that rely on how Flutter works internally. By properly setting up and initializing these components using the WidgetsFlutterBinding.ensureInitialized
function, you can prevent any problems and make your Flutter application run smoothly.