使用相机包授予权限会在异常时暂停调试器
Posted
技术标签:
【中文标题】使用相机包授予权限会在异常时暂停调试器【英文标题】:Granting permission using camera package pauses the debugger on an exception 【发布时间】:2019-11-21 23:59:54 【问题描述】:我正在使用 camera 包来实现简单的功能。我主要关注example 提供的包。当我打开摄像头小部件页面时,包会自动提示提供摄像头和麦克风的权限。单击允许这两个权限后,调试器将暂停并出现异常:
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.).
这是所需的代码:
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);
调试器在这里指出异常:
Future<void> _initialize() async
await _getCameras();
_controller = CameraController(_availableCameras[0], ResolutionPreset.high);
//-------------HERE------------------
await _controller.initialize();
if (!mounted)
return;
setState(() );
一旦我恢复调试器并尝试再次打开此相机页面,就不会再出现错误/异常。仅在第一次接受权限后才会发生。
【问题讨论】:
【参考方案1】:可能真正的罪魁祸首是didChangeAppLifecycleState
。
一旦您调用await _controller.initialize();
并显示权限对话框,就会触发生命周期事件AppLifecycleState.inactive
并根据您在didChangeAppLifecycleState
中的代码处理当前控制器,因此当应用程序在授予权限后恢复并尝试继续时,它会引发错误。
尝试删除
if (state == AppLifecycleState.inactive)
_controller?.dispose();
或者有一个局部变量来检查是否初始化并在初始化时忽略dispose
Future<void> _initialize() async
await _getCameras();
_controller = CameraController(_availableCameras[0], ResolutionPreset.high);
_initializing = true;
await _controller.initialize();
_initializing = false;
if (!mounted)
return;
setState(() );
在didChangeAppLifecycleState
if (state == AppLifecycleState.inactive && !_initializing)
_controller?.dispose();
编辑:
可能是,我想我找到了问题,实际问题是didChangeAppLifecycleState
,正如预期的那样,didChangeAppLifecycleState
中的if
子句,如果事实证明是真的,_controller
正在被处置,如果不是_setCurrentCamera
只是在处理任何活动控制器。因此,当您调用初始化并等待权限时,在权限未来解析之前,_controller
将由didChangeAppLifecycleState
处理。
我的解决方案只需进行简单的更改即可。将您的 initState
更改为
@override
void initState()
super.initState();
_initializing = true; // set to true
WidgetsBinding.instance.addObserver(this);
_initialize();
在初始化之后将_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(() );
和你的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);
这样,如果_initializing == true
你永远不会释放当前控制器。
希望有帮助!
【讨论】:
感谢您的回复。我试过了。但又是同样的问题。? 我们不能使用controller.value.isIntialized
来执行这些检查吗?
我想你可以,我只是忘了CameraController
有一个状态字段:D
试试if((!controller?.value?.isIntialized)??false) return;
你能分享一下sn-p你是怎么检查的吗?以上是关于使用相机包授予权限会在异常时暂停调试器的主要内容,如果未能解决你的问题,请参考以下文章