Wekslie
Wekslie

Reputation: 124

How should I pause the camera when navigating to new screen?

I am creating a barcode scanner functionality for a Flutter app. Most of the work has been done by the awesome guys at FlutterFire, and I'm using the example they have on their github, found here here.

My question: what would be the best way to navigate away from this screen when a barcode is found, and return when a users presses back, without leaving the camera scanning or active in the background?

Edit

The problem lies in pausing both the _camera.startImageStream, and the ScannerUtils.detect( function.

I have tried calling the _initializeCamera function after awaiting the Navigator.push, but it seems that the initialize function is not done before the view is ready.

Upvotes: 2

Views: 4045

Answers (4)

ANORAK_MATFLY
ANORAK_MATFLY

Reputation: 385

First, create a dispose() method at the top of your widget.

 @override
  void dispose() {
    controller!.stopCamera();
    controller!.dispose();
    super.dispose();
  }

Then call it before navigating to the new screen:

    dispose(); // Don't forget to call this first.

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const AuthRouter(),
      ),
    );

Upvotes: 0

UpSkills UpSkills
UpSkills UpSkills

Reputation: 41

I cannot comment.

I tested the Lulupointu's answer. It is working for me

the code has been customized as below

@override
void dispose() {
_camera.dispose().then((_) {
  _camera = null;
 });
  super.dispose();
}

Dont view the video until you cannot make it works. https://youtu.be/FozvYTtjZ3Y

Upvotes: 0

Wekslie
Wekslie

Reputation: 124

I have fixed the issue by calling this function before navigating to the new screen:

void closeCameraAndStream() async {
  if (_camera.value.isStreamingImages) {
    await _camera.stopImageStream();
}
await _camera.dispose();

setState(() {
  _camera = null;
  _scanResults = null;
});
}

Also, I re-initialize the camera on returning to the screen, using this:

Navigator.of(context)
            .push(MaterialPageRoute(builder: (BuildContext routeContextcontext) => BarcodeResultScreen(barcodeValue)))
            .then((value) {
          _initializeCamera();
        });

Upvotes: 3

Lulupointu
Lulupointu

Reputation: 3584

As far as I can see they dispose of everything for you so if you don't use their widget anymore everything will be disposed properly.

Here is the code I'm talking about:

@override
  void dispose() {
    _camera.dispose().then((_) {
      _barcodeDetector.close();
      _faceDetector.close();
      _imageLabeler.close();
      _cloudImageLabeler.close();
      _recognizer.close();
      _cloudRecognizer.close();
    });

    _currentDetector = null;
    super.dispose();
  }

Indeed when an object is removed from the widget tree, it calls its method dispose. So programmers use this to close things which aren't useful anymore (such as the camera in your case).

Please check https://api.flutter.dev/flutter/widgets/State/dispose.html to learn more about dispose.

Warning with Navigator.push

If you use Navigator.push, flutter does not destroy the widget. You should use the deactivate method to do something when Navigator.push is called. There you could either call the dispose method of their widget or hide it from your tree with a variable _isVIsible set to false. Else just use Navigator.pushReplacement which will dispose the widget as expected.

Upvotes: 0

Related Questions