boo*_*boy 3 camera dart flutter flutter-dependencies flutter-packages
我使用相机包来实现简单的功能。我主要遵循包提供的示例。当我打开相机小组件页面时,程序包会自动提示提供相机和麦克风的权限。单击允许这两种权限后,调试器将暂停,但出现异常:
Exception has occurred.
FlutterError (A CameraController was used after being disposed.
Once you have called dispose() on a CameraController, it can no longer be used.).
Run Code Online (Sandbox Code Playgroud)
这是所需的代码:
class CameraPage extends StatefulWidget {
@override
_CameraPageState createState() => _CameraPageState();
}
class _CameraPageState extends State<CameraPage>
with WidgetsBindingObserver {
CameraController _controller;
List<CameraDescription> _availableCameras;
...
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_initialize();
}
Future<void> _initialize() async {
await _getCameras();
_controller = CameraController(_availableCameras[0], ResolutionPreset.high);
await _controller.initialize();
if (!mounted) {
return;
}
setState(() {});
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.inactive) {
_controller?.dispose();
} else if (state == AppLifecycleState.resumed) {
if (_controller != null) {
_setCurrentCamera(_controller.description);
}
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_controller.dispose();
super.dispose();
}
Future<List<CameraDescription>> _getCameras() async {
List<CameraDescription> camDescriptions;
camDescriptions = await availableCameras();
_availableCameras = camDescriptions;
return camDescriptions;
}
@override
Widget build(BuildContext context) {
...
}
Future<void> _setCurrentCamera(CameraDescription cameraDescription) async {
if (_controller != null) {
await _controller.dispose();
}
_controller = CameraController(
cameraDescription,
ResolutionPreset.high,
enableAudio: false,
);
// If the _controller is updated then update the UI.
_controller.addListener(() {
if (mounted) setState(() {});
if (_controller.value.hasError) {
print('Camera error ${_controller.value.errorDescription}');
}
});
try {
await _controller.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
void _switchCamera() {
if (_controller != null && !_controller.value.isRecordingVideo) {
CameraLensDirection direction = _controller.description.lensDirection;
CameraLensDirection required = direction == CameraLensDirection.front
? CameraLensDirection.back
: CameraLensDirection.front;
for (CameraDescription cameraDescription in _availableCameras) {
if (cameraDescription.lensDirection == required) {
_setCurrentCamera(cameraDescription);
return;
}
}
}
}
void _showCameraException(CameraException e) {
String errorText = 'Error: ${e.code}\nError Message: ${e.description}';
print(errorText);
}
}
Run Code Online (Sandbox Code Playgroud)
调试器在这里指出异常:
Future<void> _initialize() async {
await _getCameras();
_controller = CameraController(_availableCameras[0], ResolutionPreset.high);
//-------------HERE------------------
await _controller.initialize();
if (!mounted) {
return;
}
setState(() {});
}
Run Code Online (Sandbox Code Playgroud)
一旦我恢复调试器并尝试再次打开此相机页面,就不再出现错误/异常。仅在第一次接受权限后才会发生。
也许真正的罪魁祸首是didChangeAppLifecycleState。
一旦您调用await _controller.initialize();并显示权限对话框,AppLifecycleState.inactive就会触发生命周期事件,并根据您在 中的代码处理当前控制器didChangeAppLifecycleState,因此当应用程序在授予权限后恢复并尝试继续时,它会抛出错误。
尝试删除
if (state == AppLifecycleState.inactive) {
_controller?.dispose();
}
Run Code Online (Sandbox Code Playgroud)
或者有一个局部变量来检查是否正在初始化并在初始化时忽略处理,例如
Future<void> _initialize() async {
await _getCameras();
_controller = CameraController(_availableCameras[0], ResolutionPreset.high);
_initializing = true;
await _controller.initialize();
_initializing = false;
if (!mounted) {
return;
}
setState(() {});
}
Run Code Online (Sandbox Code Playgroud)
并在didChangeAppLifecycleState
if (state == AppLifecycleState.inactive && !_initializing) {
_controller?.dispose();
}
Run Code Online (Sandbox Code Playgroud)
编辑:
可能是,我想我发现了这个问题,实际的问题正如didChangeAppLifecycleState预期的那样,如果结果属实,则正在处理中的if条款,如果不是,则只是处理任何活动控制器。因此,当您调用初始化并等待权限时,在权限 future 解析之前,正在由 处置。didChangeAppLifecycleState_controller_setCurrentCamera_controllerdidChangeAppLifecycleState
我的解决方案只需进行简单的更改即可工作。将您的更改initState为
@override
void initState() {
super.initState();
_initializing = true; // set to true
WidgetsBinding.instance.addObserver(this);
_initialize();
}
Run Code Online (Sandbox Code Playgroud)
初始化后更改您的_initialize函数,_initializing = false例如,
Future<void> _initialize() async {
await _getCameras();
_controller = CameraController(_availableCameras[0],ResolutionPreset.high);
await _controller.initialize();
_initializing = false; // set to false
if (!mounted) {
return;
}
setState(() {});
}
Run Code Online (Sandbox Code Playgroud)
和你didChangeAppLifecycleState的
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if(_initializing){
return;
}
if (state == AppLifecycleState.inactive) {
_controller?.dispose();
} else if (state == AppLifecycleState.resumed) {
if (_controller != null) {
_setCurrentCamera(_controller.description);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样,如果_initializing == true您从未处置当前控制器。
希望有帮助!
| 归档时间: |
|
| 查看次数: |
3142 次 |
| 最近记录: |