Камера Flutter для Android через некоторое время выдаст исключение

#flutter #android-camera2

Вопрос:

В настоящее время я создаю этот виджет экрана камеры, который будет перемещаться на другой экран при обнаружении штрих-кода водительских прав.

Мой поток приложений выглядит так:

Виджет экрана 1 -> Виджет экрана камеры ->> Виджет экрана 2 (виджет экрана 2 имеет кнопку для возврата к виджету экрана 1).

Поток будет нормально работать около 10 раз, но затем он всегда будет отображаться на виджете экрана камеры.

Вот исключение, которое выбрасывается:

 I/Camera  (24242): closeCaptureSession
E/AndroidRuntime(24242): FATAL EXCEPTION: pool-89-thread-1
E/AndroidRuntime(24242): Process: com.example.visitor_checkin_app, PID: 24242
E/AndroidRuntime(24242): java.lang.IllegalStateException: Session has been closed; further changes are illegal.
E/AndroidRuntime(24242):    at android.hardware.camera2.impl.CameraCaptureSessionImpl.checkNotClosed(CameraCaptureSessionImpl.java:886)
E/AndroidRuntime(24242):    at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:303)
E/AndroidRuntime(24242):    at io.flutter.plugins.camera.Camera.refreshPreviewCaptureSession(Camera.java:434)
E/AndroidRuntime(24242):    at io.flutter.plugins.camera.Camera.access$600(Camera.java:83)
E/AndroidRuntime(24242):    at io.flutter.plugins.camera.Camera$2.onConfigured(Camera.java:373)
E/AndroidRuntime(24242):    at android.hardware.camera2.impl.CallbackProxies$SessionStateCallbackProxy.lambda$onConfigured$0$CallbackProxies$SessionStateCallbackProxy(CallbackProxies.java:53)
E/AndroidRuntime(24242):    at android.hardware.camera2.impl.-$Lambda$CallbackProxies$SessionStateCallbackProxy$soW0qC12Osypoky6AfL3P2-TeDw.run(Unknown Source:4)
E/AndroidRuntime(24242):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime(24242):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime(24242):    at java.lang.Thread.run(Thread.java:923)
 

Версия флаттера: 2.5.1

Версия камеры: 0.9.4

Версия Android minSdk: 27

Ниже приведен код:

 import 'dart:async';
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_ml_kit/google_ml_kit.dart';

class CameraView extends StatefulWidget {
  CameraView(
      {Key? key,
      this.initialDirection = CameraLensDirection.back})
      : super(key: key);

  static const CAMERAVIEW_ROUTE = "/cameraview";
  final String title = "Barcode Scanner";
  final CameraLensDirection initialDirection;

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

class _CameraViewState extends State<CameraView> {
  BarcodeScanner barcodeScanner = GoogleMlKit.vision.barcodeScanner(const [
    BarcodeFormat.pdf417
  ]);

  bool isBusy = false;
  CameraController? _controller;
  int _cameraIndex = 0;

  @override
  void initState() {
    super.initState();

    for (var i = 0; i < cameras.length; i  ) {
      if (cameras[i].lensDirection == widget.initialDirection) {
        _cameraIndex = i;
        break;
      }
    }
    _startLiveFeed();
    isBusy = false;
  }

  @override
  void dispose() {
    _stopLiveFeed();
    barcodeScanner.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title)
      ),
      body: _body()
    );
  }

  Widget _body() {
    Widget body = _liveFeedBody();
    return body;
  }

  Widget _liveFeedBody() {
    if (_controller?.value.isInitialized == false) {
      return Container();
    }
    return Container(
      color: Colors.black,
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          CameraPreview(_controller!)
        ],
      ),
    );
  }

  Future _startLiveFeed() async {
    final camera = cameras[_cameraIndex];
    _controller = CameraController(
      camera,
      ResolutionPreset.high,
      enableAudio: false,
    );
    _controller?.initialize().then((_) {
      if (!mounted) {
        return;
      }

      _controller?.startImageStream(_processCreateInputImage);
      if (mounted) {
        setState(() {});
      }
    });
  }

  Future _stopLiveFeed() async {
    await _controller?.stopImageStream();
    await _controller?.dispose();
    _controller = null;
  }

  Future _processBarCodeImage(InputImage inputImage) async {
    final barcodes = await barcodeScanner.processImage(inputImage);
    if (barcodes.length > 0) {
      for (var i = 0; i < barcodes.length;   i) {
        Barcode bcode = barcodes[i];
        if (bcode.type == BarcodeType.driverLicense) {
          BarcodeDriverLicense bcodeDL = bcode.value as BarcodeDriverLicense;
          String scannedName = bcodeDL.lastName!   ", "   bcodeDL.firstName!;

          Navigator.of(context).popAndPushNamed(
              AnotherScreen.ANOTHER_SCREEN_ROUTE,
              arguments: ScannedInfoArguments(
                  scannedName));

          break;
        }
      }
    }
  }

  Future _processCreateInputImage(CameraImage image) async {
    if (isBusy) return;
    isBusy = true;

    final WriteBuffer allBytes = WriteBuffer();
    for (Plane plane in image.planes) {
      allBytes.putUint8List(plane.bytes);
    }
    final bytes = allBytes.done().buffer.asUint8List();

    final Size imageSize =
        Size(image.width.toDouble(), image.height.toDouble());

    final camera = cameras[_cameraIndex];
    final imageRotation =
        InputImageRotationMethods.fromRawValue(camera.sensorOrientation) ??
            InputImageRotation.Rotation_0deg;

    final inputImageFormat =
        InputImageFormatMethods.fromRawValue(image.format.raw) ??
            InputImageFormat.NV21;

    final planeData = image.planes.map(
      (Plane plane) {
        return InputImagePlaneMetadata(
          bytesPerRow: plane.bytesPerRow,
          height: plane.height,
          width: plane.width,
        );
      },
    ).toList();

    final inputImageData = InputImageData(
      size: imageSize,
      imageRotation: imageRotation,
      inputImageFormat: inputImageFormat,
      planeData: planeData,
    );

    final inputImage =
        InputImage.fromBytes(bytes: bytes, inputImageData: inputImageData);

    await _processBarCodeImage(inputImage);
    isBusy = false;
  }
}

 

С нетерпением ждем предложений и/или решений для решения этой проблемы.

Спасибо

Комментарии:

1. У меня та же проблема, ты когда-нибудь ее исправлял?