Flutter FutureBuilder相机已经初始化完成
问题描述
我是Flutter的新手,我想使用FutureBuilder制作一个简单的相机界面。这是我的代码
import 'dart:developer';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'DisplayImagePage.dart';
class CameraScreen extends StatefulWidget {
@override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
late CameraController _controller;
late final CameraDescription camera;
@override
void initState() {
super.initState();
}
Future<void> prepareCamera() async
{
_getCamera().then((CameraDescription camera)
{
_controller = CameraController(camera, ResolutionPreset.medium);
_controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
);
}
Future<CameraDescription> _getCamera() async
{
final cameras = await availableCameras();
if (cameras.isEmpty) {
// No cameras available
log("Camera is empty!");
}
final firstCamera = cameras.first;
camera = firstCamera;
return firstCamera;
}
Future<String> _takeSelfie(BuildContext context) async {
final XFile image = await _controller.takePicture();
var takenImagePath = image.path;
return takenImagePath;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Take a Selfie'),
),
body: FutureBuilder(
future: prepareCamera(),
builder: (ctx, snapshot)
{
if(snapshot.hasData)
{
log(snapshot.toString());
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: CameraPreview(_controller),
);
}
else if (snapshot.hasError)
{
return Center(
child: Text(
'${snapshot.error} occured',
style: TextStyle(fontSize: 18),
),
);
}
return Center(
child: CircularProgressIndicator(),
);
}
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
try {
var path = await _takeSelfie(context);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayImagePage(imageUrl: path),
));
} catch (e) {
print(e);
}
},
child: Icon(Icons.camera),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
在我给予相机访问权限之后,我在控制台上看到了以下错误:
“`dart Error: LateInitializationError: Field ‘camera’ has already been initialized. “` 为什么在只调用一次`_getCamera()`的情况下,它还尝试重新赋值相机? 我尝试将`_getCamera()`和`PrepareCamera`函数包装在一起,但这并没有起作用。 解决方案: 每当您的有状态的`StatefulWidget`更新时,将调用`build`方法,所以`FutureBuilder`会在每次`build`时调用`prepareCamera`。为了防止这种情况发生,我建议你将`camera`设为可为空,而不是使用`late`初始化,并将`_getCamera`的逻辑改为以下方式:
class _CameraScreenState extends State<CameraScreen> {
late CameraController _controller;
CameraDescription? camera;
// ...
}
Future<CameraDescription> _getCamera() async
{
if (camera == null) {
final cameras = await availableCameras();
if (cameras.isEmpty) {
// No cameras available
log("Camera is empty!");
}
final firstCamera = cameras.first;
camera = firstCamera;
return firstCamera;
}
return camera; // add this too
}
解决方案
每次StatefulWidget
的状态更新时,都会调用build
方法,因此FutureBuilder
将在每次构建时调用preparerecamera
。为了防止这种情况发生,我建议你让camera
为空而不是使用late
初始化,并让_getCamera
内部的逻辑像这样:
class _CameraScreenState extends State<CameraScreen> {
late CameraController _controller;
CameraDescription? camera;
// ...
}
Future<CameraDescription> _getCamera() async
{
if (camera == null) {
final cameras = await availableCameras();
if (cameras.isEmpty) {
// No cameras available
log("Camera is empty!");
}
final firstCamera = cameras.first;
camera = firstCamera;
return firstCamera;
}
return camera; // add this too
}