如何使用 SharedPreferences 初始化 CameraController?
How to initialize CameraController with SharedPreferences?
首先,我像这样初始化了我的相机控制器 (camera: ^0.9.4+11),它可以工作:
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("");
}
),
);
}
}
但现在我想从 SharedPreferences (shared_preferences: ^2.0.13) 动态加载 ResolutionPreset
。
执行此操作的好方法是什么?
我尝试这样做时失败了(添加一些变量并更改 initState
方法):
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;
});
}
出现错误:LateInitializationError: Field '_initializeControllerFuture@19039262' has not been initialized.
initState
不能是 async
方法,从 SharedPreferences
获取值是 async
函数。你不能在initState
中使用await
(或then
),我的意思是你可以使用但是代码执行不会等待它完成。所以这里发生的是你的 build
方法将 运行 早于将来从 SharedPreferences
获取值完成。而且我假设你的 _initializeControllerFuture
被标记为 late
,所以当你的 build
尝试使用它时,它仍然是 null
,这会让你得到这个错误。
解决此问题的常用方法是使用 FutureBuilder
。使用 FutureBuilder
从 SharedPreferences
获取值,在加载时显示进度指示器(它会很快,所以如果您认为可以跳过这部分),然后当您从中获取值时,使用来自 SharedPreferences
的值构建您的小部件,并仅在此之后初始化 CameraController
。
首先,我像这样初始化了我的相机控制器 (camera: ^0.9.4+11),它可以工作:
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("");
}
),
);
}
}
但现在我想从 SharedPreferences (shared_preferences: ^2.0.13) 动态加载 ResolutionPreset
。
执行此操作的好方法是什么?
我尝试这样做时失败了(添加一些变量并更改 initState
方法):
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;
});
}
出现错误:LateInitializationError: Field '_initializeControllerFuture@19039262' has not been initialized.
initState
不能是 async
方法,从 SharedPreferences
获取值是 async
函数。你不能在initState
中使用await
(或then
),我的意思是你可以使用但是代码执行不会等待它完成。所以这里发生的是你的 build
方法将 运行 早于将来从 SharedPreferences
获取值完成。而且我假设你的 _initializeControllerFuture
被标记为 late
,所以当你的 build
尝试使用它时,它仍然是 null
,这会让你得到这个错误。
解决此问题的常用方法是使用 FutureBuilder
。使用 FutureBuilder
从 SharedPreferences
获取值,在加载时显示进度指示器(它会很快,所以如果您认为可以跳过这部分),然后当您从中获取值时,使用来自 SharedPreferences
的值构建您的小部件,并仅在此之后初始化 CameraController
。