How to wait for camera to initialize?

2,409

I fixed it. I put the initializing of the camera object in the in the parent of the widget.

class _TakeReceiptPictureState extends State<TakeReceiptPicture> {
  List<CameraDescription> cameras;
  CameraDescription camera;

  @override
  void initState() { 
    super.initState();
    availableCameras().then((availableCameras) {
      cameras = availableCameras;
      camera = cameras.first;
    });       
  }

Then made the widget that takes the picture have a parameter of type CameraDescription.

class PicturePreview extends StatefulWidget {
  final CameraDescription camera;
  const PicturePreview(this.camera, {Key key}) : super(key: key);

  @override
  _PicturePreviewState createState() => _PicturePreviewState();
}

Then passed the camera initialized in the parent to picture widget

        onTap: () {
          Navigator.of(context).push(
             PageTransition(
                  type: PageTransitionType.transferRight,
                  child: PicturePreview(camera)),
            );
        }),

by the time the child widget's build method runs, the camera object is already initialized and ready to go.

Now the state of the child have only two variables, the camera controller and the initialize controller future.

  CameraController cameraController;
  Future<void> initializeController;

  @override
  void initState() {
    super.initState();    
    cameraController = CameraController(
      widget.camera,
      ResolutionPreset.low,
    );
    initializeController = cameraController.initialize();
  }

TLDR: let the initialization of the camera object be the responsibility of the parent of the widget.

Share:
2,409
MAA
Author by

MAA

Updated on December 22, 2022

Comments

  • MAA
    MAA over 1 year

    I kept getting an error from the camera.dart that "name" was being called on a null object.

    After some time, I realized that the problem was the that the build method is called before the async code in my initstate finished (I'm actually slightly proud that I understood the problem at least :))

    I tried many different ways to initialize my camera properly, but I could not. This is the last iteration of my code.

    What's the idiomatic way of handling this future?

      class _PicturePreviewState extends State<PicturePreview> {
      List<CameraDescription> cameras;
      CameraDescription camera;
      CameraController cameraController;
      Future<void> initializeController;
    
      Future<void> getCameras() async {
        try {
          cameras = await availableCameras();     
        } catch(e) {print(e);}
        camera = cameras.last;
        print(camera);
      }
    
      @override
      void initState() {
        super.initState();
        // getCameras();
        availableCameras().then((availableCameras) {
          cameras = availableCameras;
          camera = cameras.first;
          cameraController = CameraController(
          camera,
          ResolutionPreset.low,
        );
        initializeController = cameraController.initialize();
        print(cameraController.value.isInitialized);
        });
        
        // cameraController = CameraController(
        //   camera,
        //   ResolutionPreset.low,
        // );
        // initializeController = cameraController.initialize();
        // print(cameraController.value.isInitialized);
      }
    
      @override
      void dispose() {
        cameraController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: FutureBuilder<void>(
            future: initializeController,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                // If the Future is complete, display the preview.
                  return CameraPreview(cameraController);
              }
              else {
                // Otherwise, display a loading indicator.
                print(snapshot.connectionState);
                return Center(child: CircularProgressIndicator());
              }
            },
          ),
    

    I have been relying on this page to use the camera package, but I could not use it verbatim because I can't keep passing down the camera object down my widget tree.