First I have initialized my camera controller (camera: ^0.9.4 11) like this and it works:
class TakePictureScreen extends StatefulWidget {
final CameraDescription camera;
const TakePictureScreen({required Key key, required this.camera})
: super(key: key);
@override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
@override
void initState() {
super.initState();
_controller = CameraController(
widget.camera,
ResolutionPreset.max, // TODO: this should come from SharedPreferences
);
_initializeControllerFuture = _controller.initialize();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
return (snapshot.connectionState == ConnectionState.done)
? CameraPreview(_controller)
: Text("");
}
),
);
}
}
But now I want to load the ResolutionPreset
dynamically from SharedPreferences (shared_preferences: ^2.0.13).
What's a good way to do this?
I failed when trying it like this (adding some variables and changing initState
method):
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
late Future<int> _resolutionIndex;
List<ResolutionPreset> resolutions = ResolutionPreset.values.toList(growable: false);
static const String sharedPrefResolution = "resolution";
@override
void initState() {
super.initState();
_resolutionIndex = _prefs.then((SharedPreferences prefs) {
int resolutionIndex = prefs.getInt(sharedPrefResolution) ?? (resolutions.length - 1);
_controller = CameraController(
widget.camera,
resolutions[resolutionIndex],
);
_initializeControllerFuture = _controller.initialize();
return resolutionIndex;
});
}
Getting the error: LateInitializationError: Field '_initializeControllerFuture@19039262' has not been initialized.
CodePudding user response:
initState
can't be an async
method, and getting a value from SharedPreferences
is an async
function. You can't use await
(or then
) in initState
, I mean you can use but the code execution will not wait for this to complete. So what happens here is that your build
method will run earlier than the future getting the value from SharedPreferences
completes. And as I presume your _initializeControllerFuture
is marked as late
, so when your build
tries to use it, it is still null
, and that will get you this error.
The common way to solve this issue is to use a FutureBuilder
. Get the values from SharedPreferences
with FutureBuilder
, display a progress indicator while it is being loaded (it will be quick so if you think you can skip this part), and then when you get the value from it, build your widget using the value coming from SharedPreferences
, and initialize CameraController
only after this.