如何等待异步函数正确完成(flutter、dart)

How do I wait for an asynchronous function to finish correctly (flutter, dart)

提问人:JohannesBug 提问时间:7/13/2023 更新时间:7/13/2023 访问量:37

问:

我想为一个显示相机预览的 flutter 应用程序构建一个屏幕。为此,我必须异步初始化相机。这会导致异常,因为我在初始化相机之前访问了它。我通过使用 try-catch 块来解决这个问题。但我觉得这是一个肮脏的解决方案。有没有更好的?我正在 android 的 Windows 上开发。这是我为该屏幕编写的完整代码。我用行注释标记了兴趣点。

import 'package:flutter/material.dart';
import 'package:camera/camera.dart';

class CameraPreviewPage extends StatefulWidget {
  const CameraPreviewPage({super.key});

  @override
  State<CameraPreviewPage> createState() => _CameraPreviewPageState();
}

class _CameraPreviewPageState extends State<CameraPreviewPage> {
  late List<CameraDescription> _cameraDescriptions;
  late CameraController _cameraController; //Here I declare the camera object which throws an "late not inizialized" exception

//this function inizializes the object but asynchronously
  void initCamera() async {
    _cameraDescriptions = await availableCameras();
    _cameraController = CameraController(
      _cameraDescriptions[0],
      ResolutionPreset.high,
      enableAudio: false,
    );
    await _cameraController.initialize().then((value) {
      if (!mounted) {
        return;
      }
      setState(() {});
    }).catchError((e) {
      debugPrint(e);
    });
  }

  @override
  void dispose() {
    _cameraController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    initCamera();
    super.initState();
  }

//in this build function the Exception occurs.
// Wrapping the "CameraPreview(_cameraController)," line in a try catch gives me working but ugly(?) code
  @override
  Widget build(BuildContext context) {
    try {
      return Scaffold(
        body: Stack(
          children: [
            CameraPreview(_cameraController),
          ],
        ),
      );
    } catch (e) {
      return const SizedBox();
    }
  }
}

我对异步编程和 flutter/dart 本身很陌生。如果这个问题在其他地方得到解答,请把我带到那里,因为我在 google/youtube 上找不到它。

我尝试了 FutureBuilder Widget,但它无法正常工作,也许我不理解它,可悲的是我丢失了代码。

Android Flutter Dart 异步

评论


答:

1赞 Niko 7/13/2023 #1

问题是它本身不是一个异步方法,不能等待你的.因此,当方法已被调用时,您正在执行。initStateinitCamerainitCamerabuild

然后 your 尚未初始化,而是在 build 方法中使用。_cameraController

要解决此问题,您可以根据状态有条件地显示不同的小部件,或者改用小部件。FutureBuilder

使用布尔值时的状态类:

class _CameraPreviewPageState extends State<CameraPreviewPage> {
  late List<CameraDescription> _cameraDescriptions;
  late CameraController _cameraController; //Here I declare the camera object which throws an "late not inizialized" exception
  bool _initialized = false;

//this function inizializes the object but asynchronously
  void initCamera() async {
    _cameraDescriptions = await availableCameras();
    _cameraController = CameraController(
      _cameraDescriptions[0],
      ResolutionPreset.high,
      enableAudio: false,
    );
    await _cameraController.initialize().then((value) {
      if (!mounted) {
        return;
      }
      setState(() {
        _initialized = true;
      });
    }).catchError((e) {
      debugPrint(e);
    });
  }

  @override
  void dispose() {
    _cameraController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    initCamera();
    super.initState();
  }

//in this build function the Exception occurs.
// Wrapping the "CameraPreview(_cameraController)," line in a try catch gives me working but ugly(?) code
  @override
  Widget build(BuildContext context) {
    try {
      return Scaffold(
        body: Stack(
          children: [
            if(_initialized) CameraPreview(_cameraController),
            if(!_initialized) Text("loading..."),
          ],
        ),
      );
    } catch (e) {
      return const SizedBox();
    }
  }
}