Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

I want to build a screen for a flutter app which shows a camera preview. To achieve this I have to initialize the camera asynchronously. This leads to an exception because I access the camera before it is initialized. I work around that with using a try-catch block. But this strikes me as a dirty solution. Is there a better one? I am developing on windows for android. here is my full code for that screen. I marked the points of interest with line comments.

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();
    }
  }
}

I am pretty new to asynchronous programming and to flutter/dart itself. If this question gets answered somewhere else plsease lead me there because I couldn’t find it on google/youtube.

I tried the FutureBuilder Widget but it did not work correctly, maybe I didn’t understand it and sadly I lost the code.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The problem is that initState itself is not an async method and cannot await your initCamera. So your initCamera is executing while your build method is already being called.

And then your _cameraController is not initialized yet, but used inside of your build method.

To fix this, you can conditionally show different widgets depending on a state bool, or use a FutureBuilder widget instead.

Your state class when using a bool:

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();
    }
  }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading