Flutter FutureBuilder camera has been intialized already

I’m new to Flutter and I want to make a simple camera screen using FutureBuilder. This is my code

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

After I give permission to the camera acces, I see this error on the console:
Error: LateInitializationError: Field 'camera' has already been initialized.

_getCamera() is only called once why it tries to assign camera again?

I have tried to wrap _getCamera and PrepareCamera functions together. This did not work.

The build method is called everytime the state of your StatefulWidget is updated, so the FutureBuilder will call prepareCamera on every build. To prevent this, I suggest you to make camera nullable instead of using late initilization, and make the logic inside _getCamera like this:

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
}

Leave a Comment