0

Scenario

I am trying to launch a camera stream screen in my Flutter app in order to capture a selfie using google_ml_kit_face_detection. For this purpose, I need to set a ResolutionPreset to my CameraController object. I am using the camera plugin for Flutter.

I am obtaining the phone's RAM from system_info_plus which returns a Future<int?>.

In my initState() I am calling the function to obtain the RAM value, and then calling the function to initialize the CameraController object by passing the ResolutionPreset based on the phone's RAM.

My Code

CameraController? _controller;
int? deviceMemory;

@override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      await getDeviceMemory();
      initCameraLens();
      await startLive();
    });
  }

Future<void> getDeviceMemory() async {
    deviceMemory = await SystemInfoPlus.physicalMemory; // returns in MB
  }

void initCameraLens() {
    // relevant code
  }

Future<void> startLive() async {
    final camera = cameras[_cameraIndex];

    // setup camera controller
    _controller = CameraController(
      camera,
      deviceMemory != null
          ? deviceMemory! <= 3072
              ? ResolutionPreset.low
              : ResolutionPreset.high
          : ResolutionPreset.high,
      enableAudio: false,
    );

    // start streaming using camera
    _controller?.initialize().then((_) {
      if (!mounted) {
        return;
      }

      // process camera image to get an instance of input image
      _controller?.startImageStream(_processCameraImage);

      setState(() {});
    });
  }

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: [
          _controller != null ?
            CameraPreview(_controller!) :
            Container(
              width: 100.w,
              height: 100.h,
              color: Colors.black,
            ),
         ],
       ),
    ),
  }

Issue Faced

When this screen launches, for a brief second or two I get the following error: The following _CastError was thrown building CaptureFaceScreen(dirty, state: _CaptureFaceScreenState#38f97): Null check operator used on a null value after which the camera starts working and everything runs smoothly from thereon.

Request

I would like to know what's causing this exception in my code and how to fix this issue.

Ayan Dasgupta
  • 304
  • 1
  • 4
  • 11

2 Answers2

0

I think the getDeviceMemory() is not quick enough. So try to add a .then next to it instead, that way it wont continue until getDeviceMemory() is complete.

@override
void initState() {
  super.initState();
  getDeviceMemory().then((value) {
    initCameraLens();
    startLive();
  });
}

You shouldnt need to use WidgetsBinding.instance.addPostFrameCallback((_)

Texv
  • 1,225
  • 10
  • 14
  • I think the await with getDeviceMemory() does exactly the same thing. It waits for getDeviceMemory() to complete. – Niladri Raychaudhuri Apr 22 '23 at 04:14
  • I am alreasy using await with getDeviceMemory(). – Ayan Dasgupta Apr 22 '23 at 04:27
  • Can you try it though? From my experience i find that sometimes the asynchronous is a bit slow. Since your controller is initially a null value, the ui that was built says your _controller is null but then goes away after completing the asynchronous function. Please read more about the difference from the correct answer of this post: https://stackoverflow.com/questions/54515186/async-await-then-in-dart-flutter#:~:text=A%20Flutter%20question%20from%20an,the%20async%20method%20is%20finished. – Texv Apr 22 '23 at 04:34
  • or perhaps you can try to add _loading=true and _loading=false inside getDeviceMemory() so you can stop the UI from building until your controller is initialized – Texv Apr 22 '23 at 04:41
0

I managed a workaround by initializing the the CameraController object with some static data before setting the desired values via the relevant functions in initState() calls.

Instead of:

CameraController? _controller;

I am doing:

CameraController _controller = CameraController(
    const CameraDescription(
      name: "",
      lensDirection: CameraLensDirection.front,
      sensorOrientation: 90,
    ),
    ResolutionPreset.high,
    enableAudio: false,
  );
Ayan Dasgupta
  • 304
  • 1
  • 4
  • 11