'flutter - error in accessing camera

I am creating an app in which I need to use camera of mobile device. I have created below class

class CameraWidget extends StatefulWidget {
  @override
  _CameraWidgetState createState() => _CameraWidgetState();
}

class _CameraWidgetState extends State<CameraWidget> {
  List<CameraDescription> cameras;
  CameraController controller;
  bool isReady= false;

//  @override
//  void initState() {
//    super.initState();
//    _setupCamera();
//  }

  Future<void> _setupCamera() async {
    try {
      // initialize cameras.
      cameras = await availableCameras();
      // initialize camera controllers.
      controller = new CameraController(cameras[1], ResolutionPreset.medium);
      await controller.initialize();
    } on CameraException catch (_) {
      //debugPrint("Some error occured!").
    }
    if (!mounted) return;
    setState(() {
      isReady = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new FutureBuilder(
        future: _setupCamera(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (!isReady) {
            return new Container();
          }
          return new Center(
            child: new AspectRatio(
            aspectRatio: controller.value.aspectRatio,
            child: new CameraPreview(controller))
          );
        }
    );
  }
}

I am not getting any error with above code but my application is getting exited everytime after few seconds. I am not sure what is going on.Below is the application log.

Launching lib/main.dart on Android SDK built for x86 in debug mode...
Initializing gradle...
Resolving dependencies...
Running 'gradlew assembleDebug'...
Built build/app/outputs/apk/debug/app-debug.apk.
Installing build/app/outputs/apk/app.apk...
I/FlutterActivityDelegate(17280): onResume setting current activity to this
Syncing files to device Android SDK built for x86...
I/CameraManagerGlobal(17280): Connecting to camera service
D/        (17280): HostConnection::get() New Host Connection established 0xe8b07a80, tid 17330
D/EGL_emulation(17280): eglMakeCurrent: 0xf0465a00: ver 2 0 (tinfo 0xe8b03370)
D/        (17280): HostConnection::get() New Host Connection established 0xe8b078c0, tid 17337
D/        (17280): HostConnection::get() New Host Connection established 0xe8b07540, tid 17316
D/        (17280): HostConnection::get() New Host Connection established 0xe8b07200, tid 17315
D/        (17280): HostConnection::get() New Host Connection established 0xe71fd100, tid 17350
I/zygote  (17280): Do partial code cache collection, code=30KB, data=27KB
I/zygote  (17280): After code cache collection, code=30KB, data=27KB
I/zygote  (17280): Increasing code cache capacity to 128KB
D/        (17280): HostConnection::get() New Host Connection established 0xe8b07b00, tid 17395
I/zygote  (17280): Do partial code cache collection, code=60KB, data=49KB
I/zygote  (17280): After code cache collection, code=60KB, data=49KB
I/zygote  (17280): Increasing code cache capacity to 256KB
I/zygote  (17280): Do full code cache collection, code=122KB, data=84KB
I/zygote  (17280): After code cache collection, code=116KB, data=69KB
D/        (17280): HostConnection::get() New Host Connection established 0xcb67d7c0, tid 17694
D/        (17280): HostConnection::get() New Host Connection established 0xe8b07580, tid 17695
I/zygote  (17280): Do partial code cache collection, code=121KB, data=82KB
I/zygote  (17280): After code cache collection, code=121KB, data=82KB
I/zygote  (17280): Increasing code cache capacity to 512KB
D/        (17280): HostConnection::get() New Host Connection established 0xd1360580, tid 17813
W/zygote  (17280): Long monitor contention with owner main (17280) at void android.hardware.camera2.impl.CameraDeviceImpl.close()(CameraDeviceImpl.java:1046) waiters=0 in void android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks.onCaptureStarted(android.hardware.camera2.impl.CaptureResultExtras, long) for 142ms
W/zygote  (17280): Long monitor contention with owner main (17280) at void android.hardware.camera2.impl.CameraDeviceImpl.close()(CameraDeviceImpl.java:1046) waiters=0 in void android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks.onResultReceived(android.hardware.camera2.impl.CameraMetadataNative, android.hardware.camera2.impl.CaptureResultExtras) for 179ms
W/zygote  (17280): Long monitor contention with owner main (17280) at void android.hardware.camera2.impl.CameraDeviceImpl.close()(CameraDeviceImpl.java:1046) waiters=0 in void android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks.onResultReceived(android.hardware.camera2.impl.CameraMetadataNative, android.hardware.camera2.impl.CaptureResultExtras) for 150ms
W/zygote  (17280): Long monitor contention with owner main (17280) at boolean android.os.BinderProxy.transactNative(int, android.os.Parcel, android.os.Parcel, int)(Binder.java:-2) waiters=0 in void android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks.onCaptureStarted(android.hardware.camera2.impl.CaptureResultExtras, long) for 109ms
W/zygote  (17280): Long monitor contention with owner main (17280) at boolean android.os.BinderProxy.transactNative(int, android.os.Parcel, android.os.Parcel, int)(Binder.java:-2) waiters=0 in void android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks.onCaptureStarted(android.hardware.camera2.impl.CaptureResultExtras, long) for 130ms
Lost connection to device.

Can someone please let me know whats wrong in above code?

EDIT 1- I have analyzed it futher and found that Future builder is calling builder multiple times. I think I should add some break condiation over there. but i am not getting the same from documentation that builder will be called multiple times. But changes build method as below works properly.

  @override
  Widget build(BuildContext context) {
    if (controller == null || !controller.value.isInitialized) {
      return new Container();
    }
    return new AspectRatio(
        aspectRatio: controller.value.aspectRatio,
        child: new CameraPreview(controller));
  }

Still it will be great if someone will explain it further. I am still debugging it. :)



Solution 1:[1]

The issue here is that the Camera is being initialized by the FutureBuilder every time the screen rebuilds after calling setState(). What you can do here is use controller.value.isInitialized as a checker to verify if the Camera has been initialized before initializing the Camera. Another approach that you can consider is initializing the Camera once during initState instead of inside FutureBuilder.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Omatt