Flutter :已处置的 CameraController,在已处置的 CameraController 上调用了 buildPreview()

2024-05-23

如何正确初始化和处理相机控制器。我在用camera: ^0.9.4+5

与许多人一起

其他错误 https://stackoverflow.com/questions/70592464/flutter-change-the-path-of-recorded-video

我在单击切换相机按钮时收到此错误:

======== Exception caught by widgets library =======================================================
The following CameraException was thrown building ValueListenableBuilder<CameraValue>(dirty, state: _ValueListenableBuilderState<CameraValue>#47f17):
CameraException(Disposed CameraController, buildPreview() was called on a disposed CameraController.)

这是完整的代码:

class VideoRecorderScreen extends StatefulWidget {
  @override
  _VideoRecorderScreenState createState() {
    return _VideoRecorderScreenState();
  }

  //final ApplicantData applicantData;
  final String videorec;
 

  VideoRecorderScreen(this.applicationId, this.name, this.description,
      this.descriptionHindi, this.videorec,
      {this.isOpenSubsDashboard = false});
}

class _VideoRecorderScreenState extends State<VideoRecorderScreen> {
  CameraController controller;
  XFile videoPath;
  List<CameraDescription> cameras;
  int selectedCameraIdx = 1;
  int videoElapseTime = 25;
  int videoMinElapseTime = 20;
  
  bool visibilityStop = false;
  bool visibilityButtons = false;
  String timer = "00:00";
  CountdownTimer cd;
  bool startRecording = false;

void _reset() {
    videoPath = null;
    _changed(false);
    _changedTimer("00:00");
    _changedButtonVisibility(false);
  }

  void _changed(bool visibility) {
    if (mounted) setState(() {
      visibilityStop = visibility;
    });
  }

  void _changedTimer(String time) {
    if (mounted) setState(() {
      timer = time;
    });
  }

  void _changedButtonVisibility(bool visibility) {
    if (mounted) setState(() {
      visibilityButtons = visibility;
    });
  }

  void _navigateAndDisplaySelection(BuildContext context) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => VideoPlayerScreen(
              videoPath: videoPath.path,
              applicationId: widget.applicationId,
              name: widget.name,
              dateTime: selectedDate,
              isOpenSubsDashboard: widget.isOpenSubsDashboard)),
    );

    if (result) {
      _reset();
    }
  }


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

    WidgetsBinding.instance.addPostFrameCallback((_) =>
        showSnackBar('User Validated Successfully! Welcome ' + widget.name));

   
    availableCameras().then((availableCameras) {
      cameras = availableCameras;

      if (cameras.length > 0) {
      
        for (int i = 0; i < cameras.length; i++) {
          if (cameras[i].lensDirection == CameraLensDirection.front) {
            if (mounted) setState(() {
              selectedCameraIdx = i;
            });
          }
        }

        _onCameraSwitched(cameras[selectedCameraIdx]).then((void v) {});
      }
    }).catchError((err) {
      print('Error: $err.code\nError Message: $err.message');
    });
  }


  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size.width * (2 / 3);
    return WillPopScope(
      onWillPop: _onBackPressed,
      child: Scaffold(
          key: _scaffoldKey,
          appBar: AppBarWidget(
            title: 'Record Your Video',
              actions: [
              IconButton(
                  icon: Icon(
                    Icons.call,
                   
                  ),
                  onPressed: () {
                    ConstantMethods.callToSupport();
                  }),
              AppBarLogo(),
            ],
          ),
          body: Builder(builder: (BuildContext buildContext) {
            scaffold = Scaffold.of(buildContext);
            return Container(
                   child: ListView(
            
              children: <Widget>[
              
           Center(
                                  child: Container(
                                width: size / 1.5,
                                height: size / 1.5,
                                
                              Container(
                                padding: EdgeInsets.all(5.0),
                                color: Colors.grey[850],
                                child: Text(
                                    selectedDate != null ? selectedDate : "",
                                    textAlign: TextAlign.start,
                                    
                              ),
                            ],
                          ),
                        ))
                    : Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                          VerticalSpacing(20.0),
                          Padding(
                              padding:
                                  const EdgeInsets.only(left: 8.0, right: 8.0),
                              child: Text(
                                  'Click on video icon to start the recording',
                                  textAlign: TextAlign.justify,
                                 
                          FlatButton(
                         child: Text(' Proceed for Recording '),
                            onPressed: () {
                              if (mounted) setState(() {
                                startRecording = true;
                              });
                            },
                          ),
                          VerticalSpacing(10.0),
                          FlatButton(

                            textColor: ThemeColors.colorPrimary,
                            VerticalSpacing(20.0),
                        ],
                      ),
                startRecording
                    ? Padding(
                        padding: const EdgeInsets.all(5.0),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: <Widget>[
                            _cameraTogglesRowWidget(),
                          
                            _captureControlRowWidget(),
                            Expanded(
                              child: Text("$timer",
                                  textAlign: TextAlign.end,
                                  style: TextStyle(
                                      fontSize: Consts.fontSizeMedium)),
                            ),
                          ],
                        ),
                      )
                    : new Container(),
              
                !visibilityButtons
                    ? Column(
                   
                        children: [
                          Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              //alignment: Alignment.bottomRight,
                              children: [
                                IconButton(
                                  icon: const Icon(Icons.info_outline,
                                      size: 25.0),
                                  color: ThemeColors.colorPrimary,
                                  onPressed: () {
                                    showDialog(
                                      context: context,
                                      builder: (BuildContext context) =>
                                          MessageDialog(
                                        title: "ImportantTips",
                                        message: Languages.of(context)
                                            .videoPreInstruction,
                                      ),
                                    );
                                  
                                  },
                                ),
                                ToggleButtons(
                                  borderColor: ThemeColors.colorAccent,
                                  fillColor: Colors.lightBlue[100],
                                  borderWidth: 1,
                                  selectedBorderColor: ThemeColors.colorAccent,
                                  selectedColor: Colors.blue[900],
                                  color: ThemeColors.colorPrimary,
                                  borderRadius: BorderRadius.circular(10),
                                  children: <Widget>[
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          left: 12.0, right: 8.0),
                                      child: Text(
                                        'In English',
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            fontSize: Consts.fontSizeSmall),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          left: 8.0, right: 8.0),
                                      child: Text(
                                        'हिंदी में       ',
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            fontSize: Consts.fontSizeSmall),
                                      ),
                                    ),
                                  ],
                                  onPressed: (int index) {
                                    if(this.mounted) setState(() {
                                      for (int i = 0;
                                          i < isSelectedLanguage.length;
                                          i++) {
                                        if (i == index) {
                                          isSelectedLanguage[i] = true;
                                        } else {
                                          isSelectedLanguage[i] = false;
                                        }
                                      }
                                      if (isSelectedLanguage[0]) {
                                        changeLanguage(context, 'en');
                                      } else if (isSelectedLanguage[1]) {
                                        changeLanguage(context, 'hi');
                                      }
                                    });
                                  },
                                  isSelected: isSelectedLanguage,
                                )
                              ]),
                          VerticalSpacing(10.0),
                        
                          Padding(
                              padding:
                                  const EdgeInsets.only(left: 8.0, right: 8.0),
                              child
                    : Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          OutlineButton(
                            padding: EdgeInsets.all(5.0),
                            splashColor: Colors.blue[300],
                            borderSide:
                                BorderSide(color: ThemeColors.colorPrimary),
                            child: Text(' Retake Video ',
                                style: TextStyle(
                                    color: Colors.blue,
                                    fontSize: Consts.fontSizeMedium)),
                            onPressed: () {
                              _reset();
                            },
                          ),
                          HorizontalSpacing(10.0),
                          FlatButton(
                            padding: EdgeInsets.all(5.0),
                            color: ThemeColors.colorPrimary,
//            splashColor: Colors.greenAccent,
                            textColor: ThemeColors.white,

                            child: Text(' Play Recording ',
                                style:
                                    TextStyle(fontSize: Consts.fontSizeMedium)),
                            onPressed: () {
                              if(videoPath!=null) {
                                _navigateAndDisplaySelection(context);
                              } else{
                                //ConstantMethods.showToast("Technical exception with camera.");
                                ConstantMethods.showToast("There is some issue in recording video right now, please try again later.");
                                _onBackPressed();
                              }
                            },
                          ),
                        ],
                      ),
                VerticalSpacing(10.0),
              ],
            ));
          })),
    );
  }

  IconData _getCameraLensIcon(CameraLensDirection direction) {
    switch (direction) {
      case CameraLensDirection.back:
        return Icons.camera_rear;
      case CameraLensDirection.front:
        return Icons.camera_front;
      case CameraLensDirection.external:
        return Icons.camera;
      default:
        return Icons.device_unknown;
    }
  }

  // Display 'Loading' text when the camera is still loading.
  Widget _cameraPreviewWidget(var size) {
    if (controller == null || !controller.value.isInitialized) {
      return const Text(
        'Loading',
        style: TextStyle(
          color: ThemeColors.white,
          fontSize: 20.0,
          fontWeight: FontWeight.w900,
        ),
      );
    }

    return Container(
      width: size,
      height: size,
      child: ClipRect(
        child: OverflowBox(
          alignment: Alignment.center,
          child: FittedBox(
            fit: BoxFit.fitWidth,
            child: Container(
              width: size,
              height: size / controller.value.aspectRatio,
//              height: size / controller.value.aspectRatio,
              child: CameraPreview(controller),

              // this is my CameraPreview
            ),
          ),
        ),
      ),
    );

    
  }

  /// Display a row of toggle to select the camera (or a message if no camera is available).
  Widget _cameraTogglesRowWidget() {
    if (cameras == null) {
      return Row();
    }

    CameraDescription selectedCamera =
        cameras[selectedCameraIdx]; 
    CameraLensDirection lensDirection =
        selectedCamera.lensDirection; 
    //CameraLensDirection lensDirection = CameraLensDirection.front;

    return Expanded(
      child: Align(
        alignment: Alignment.centerLeft,
        child: FlatButton.icon(
            onPressed: controller != null && controller.value.isRecordingVideo
                ? null
                : _onSwitchCamera,
            icon: Icon(_getCameraLensIcon(lensDirection)),
            label: Text(
                "${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1)}")),
      ),
    );
  }

  /// Display the control bar with buttons to record videos.
  Widget _captureControlRowWidget() {
    return Expanded(
      child: Align(
        alignment: Alignment.center,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            IconButton(
              icon: const Icon(Icons.videocam, size: 40.0),
              color: ThemeColors.colorPrimary,
              onPressed: controller != null &&
                      controller.value.isInitialized &&
                      !controller.value.isRecordingVideo &&
                      videoPath == null
                  ? _onRecordButtonPressed
                  : null,
            ),
            IconButton(
              icon: const Icon(Icons.stop, size: 40.0),
              color: ThemeColors.red,
              onPressed: controller != null &&
                      controller.value.isInitialized &&
                      controller.value.isRecordingVideo &&
                      visibilityStop
                  ? _onStopButtonPressed
                  : null,
            ),
//                : new Container(),
          ],
        ),
      ),
    );
  }

  String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

  Future<void> _onCameraSwitched(CameraDescription description) async {

      if (description == null) {
        return;
      }
      if(!(controller != null && controller.value.isRecordingVideo)){
        onNewCameraSelected(description);
      }

    
  }

  void onNewCameraSelected(CameraDescription cameraDescription) async {
    if (controller != null) {
      await controller.dispose();
    }

    controller = CameraController(
      cameraDescription, ResolutionPreset.low
    );

    //controller = cameraController;

    // If the controller is updated then update the UI.
    controller.addListener(() {
      if (mounted) setState(() {});
      if (controller.value.hasError) {
        Fluttertoast.showToast(
            msg: 'Camera error ${controller.value.errorDescription}',
            toastLength: Toast.LENGTH_SHORT,
            gravity: ToastGravity.CENTER,
            timeInSecForIosWeb: 1,
            backgroundColor: ThemeColors.red,
            textColor: ThemeColors.white);
      }
    });

    try {
      await controller.initialize();
    } on CameraException catch (e) {
      _showCameraException(e);
    }

    if (mounted) {
      setState(() {});
    }
  }

  void _onSwitchCamera() {
    selectedCameraIdx =
        selectedCameraIdx < cameras.length - 1 ? selectedCameraIdx + 1 : 0;
    CameraDescription selectedCamera = cameras[selectedCameraIdx];

    _onCameraSwitched(selectedCamera);

    if (mounted) setState(() {
      selectedCameraIdx = selectedCameraIdx;
    });
  }

  void _onRecordButtonPressed() {
    _startVideoRecording().then((_) {
      /*if (mounted) setState(() {});*/
      //if (filePath != null) {
      final df = new DateFormat('dd-MM-yyyy hh:mm a');
      String date = df.format(new DateTime.now());

      if (mounted) setState(() {
//          selectedDate = date1.replaceAll("/", "-");
        selectedDate = date;
      });

      Fluttertoast.showToast(
          msg: 'Recording video started',
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.CENTER,
          timeInSecForIosWeb: 1,
          backgroundColor: ThemeColors.grey,
          textColor: ThemeColors.white);
      // }
    });
  }

  void _onStopButtonPressed() {
    if (cd.isRunning) {
      cd.cancel();
    }

    _stopVideoRecording().then((file) {
      if (mounted) setState(() {});
      if (file != null) {
        showInSnackBar('Video recorded to ${file.path}');
        videoPath = file;
      }

    });
  }

  Future<void> _startVideoRecording() async {
    //final CameraController? cameraController = controller;

    if (controller == null || !controller.value.isInitialized) {
      //showInSnackBar('Error: select a camera first.');
      Fluttertoast.showToast(
          msg: 'Please wait',
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.CENTER,
          timeInSecForIosWeb: 1,
          backgroundColor: ThemeColors.grey,
          textColor: ThemeColors.white);

      return;
    }

    if (controller.value.isRecordingVideo) {
      // A recording is already started, do nothing.
      return;
    }

    try {
      cd = CountdownTimer(
          new Duration(seconds: videoElapseTime), new Duration(seconds: 1));
//      var sub = cd.listen(null);
      var sub = cd.listen(null);
      sub.onData((duration) {
//        setState(() { _current = _start - duration.elapsed.inSeconds; });
        if (duration.elapsed.inSeconds == videoMinElapseTime) {
            // ((videoElapseTime - 5) < 20 ? 20 : (videoElapseTime - 5))) {
          _changed(true);
        }
        timer = duration.elapsed.inMinutes.toString().padLeft(2, '0') +
            ":" +
            duration.elapsed.inSeconds.toString().padLeft(2, '0');
        _changedTimer(timer + "/00:" + videoElapseTime.toString());
        print(timer);
      });

      sub.onDone(() {
        print("Done");
        _onStopButtonPressed();
        sub.cancel();
      });
      await controller.startVideoRecording();
    } on CameraException catch (e) {
      _showCameraException(e);
      return;
    }
  }




  Future<XFile> _stopVideoRecording() async {
  
    if (controller == null || !controller.value.isRecordingVideo) {
      return null;
    }

    try {
      _changedButtonVisibility(true);
      XFile video = await controller.stopVideoRecording();
      await GallerySaver.saveVideo(video.path); //for testing
      return video;
    } on CameraException catch (e) {
      _showCameraException(e);
      return null;
    }
   
  }

  void _showCameraException(CameraException e) {
    String errorText = 'Error: ${e.code}\nError Message: ${e.description}';
    print(errorText);
}
  
  Future<bool> _onBackPressed() {
    if (widget.isOpenSubsDashboard && (role == null || role.isEmpty)) {
      //subscriber
      return Navigator.pushAndRemoveUntil(
            context,
            MaterialPageRoute(builder: (context) => SubscriberDashboard()),
            (route) => false,
          ) ??
          false;
    } else {
      //Navigator.of(context).pop();
      return Future.value(Navigator.of(context).canPop());
    }
  }

 

解决此问题的一种方法是使用 WidgetsBindingObserver - 这有助于管理应用程序的生命周期。继承你的 WidgetsBidingObserver_VideoRecorderScreenState类以正确处理相机。在此演示了类似的方法GitHub 问题线程 https://github.com/flutter/flutter/issues/58187#issuecomment-636189371.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter :已处置的 CameraController,在已处置的 CameraController 上调用了 buildPreview() 的相关文章

随机推荐

  • 如何设置响应文件名而不强制“另存为”对话框

    我在某些响应中返回一个流 设置适当的content type标头 我正在寻找的行为是这样的 如果浏览器能够呈现给定内容类型的内容 那么它应该将其显示在浏览器窗口中 如果浏览器不知道如何呈现内容 那么它应该显示 另存为 对话框 其中文件名应该
  • Angular 4:类型“AbstractControl”上不存在属性“push”和“controls”

    我从这个链接实现了代码http plnkr co edit yV94ZjypwBgHAlb0RLK2 p preview http plnkr co edit yV94ZjypwBgHAlb0RLK2 p preview但获取推送和控制错误
  • GET 错误:ModuleNotFoundError:没有名为“api”的模块

    当我尝试运行 pytest 命令时出现错误 错误是当我在 docker 上运行应用程序时 当我在本地执行时 它可以工作 还有另一个好奇心 swagger 和 de requests 工作正常 只是测试文件不行 我已经尝试过 python m
  • 在 UITableViewCell 内动态更改标签宽度

    我正在尝试建立一个自定义表格视图 正如您在图片中看到的 我在故事板一侧将标签的宽度默认设置为 160 磅 并在加载表格时动态更改宽度 我通过修改 cellForRowAtIndexPath 委托方法来实现此目的 因此 根据日期的长度 我设置
  • 构造函数初始化列表中的执行顺序

    构造函数初始化列表中的执行顺序是否可以确定 我知道类中的成员顺序是初始化这些成员的顺序 但是如果我有这样的场景 class X X Implementation impl and then providing that allocator
  • 如何更改android Activity标签

    我创建了一个活动并在清单文件中声明 但我想将相同的活动重新用于其他目的
  • 为什么tcp终止需要4次握手?

    当连接建立时 有 客户端 SYN gt 服务器 客户端 客户端 ACK gt 服务器 当终止到来时 有 客户端 FIN gt 服务器 客户端 客户端 客户端 ACK gt 服务器 我的问题是为什么 和 不能像 那样设置在同一个包中 即ACK
  • 流程验证时 selectManyCheckbox LazyInitializationException

    看来 如果您使用由 hibernate 代理的集合支持的 selectManyCheckbox 您将遇到可怕的 LazyInitializationException 问题 这与支持 bean 的状态无关 调试 Mojarra 2 1 后
  • 如何为所有整数类型创建通用整数到十六进制函数?

    我想为所有整数类型创建一个整数到十六进制函数 对于1字节的Int8 它返回两个字母 例如0A 对于2字节的Int16 它返回四个字母 例如0A0B 对于8字节的Int64 它返回16个字母 例如0102030405060708 func h
  • 黑莓 Facebook SDK jar 文件

    大家好 我在使用 Facebook Blackberry SDK 以及如何在我的项目中使用它时遇到问题 我有一个使用 SourceForge 上提供的源文件制作的项目 我在我正在开发的项目中引用了这个项目 非常适合编程 但是当我想在模拟器上
  • Android 自定义文件扩展名

    我希望我的 Android 应用程序能够通过蓝牙 电子邮件 wifi direct 等 标准共享方法 共享文件 我想将我的数据解析为具有自定义扩展名的文件 并通过某种共享方法 例如蓝牙 发送它 收件人应该能够打开该文件 然后我的应用程序启动
  • Java中的“final class”有什么意义?

    我正在读一本关于Java的书 它说你可以将整个类声明为final 我想不出我会在哪里使用它 我是编程新手 我想知道如果程序员真的在他们的程序中使用这个 如果他们这样做 他们什么时候使用它 以便我可以更好地理解它并知道何时使用它 如果Java
  • 使用 Pkg.add 时出现 julia 错误

    我刚刚在ubuntu中安装了julia 在添加包时发现了一些问题 julia gt Pkg Add Gadfly ERROR UndefVarError Add not defined 我也尝试更新 julia 但弹出错误 julia gt
  • 了解 SQL Server 排序规则中的 Unicode 和代码页

    为什么所有 SQL Server 2008 R2 排序规则都与代码页相关联 所有排序规则都是 unicode 吗 当您的数据库被使用不同代码页的多种语言使用时 如何选择排序规则 谢谢 CHAR 与 NCHAR 即非 Unicode 与 Un
  • 如何确定特定文件实际上是 MP3 文件?

    如何确定特定文件 可能有也可能没有 mp3 文件扩展名 实际上是 MP3 文件 我希望在 C 中做到这一点 根据http www garykessler net library file sigs html http www garykes
  • 以编程方式绑定 WPF 中的附加属性

    我在用着杰森 坎普很酷CueBanner class http www ageektrapped com blog the missing net 4 cue banner in wpf i mean watermark in wpf 对于
  • 为什么 C# ProcessStartInfoRedirectStandardOutput 会导致 xcopy 进程失败

    这有点痛苦 因为我现在没有代码 但我会尽力解释 我有一个简单的 C 应用程序 它启动 Ruby 脚本 它还执行一些其他操作 因此它生成一个批处理文件并执行该文件 我正在使用 C 进程对象并设置以下内容 重定向标准输出 true 重定向标准错
  • 有人可以解释一下 Postgresql 角色、Postgresql 用户和 Linux 用户之间的关系吗?

    我正在尝试在 Ubuntu 14 服务器上设置 Postgres 9 3 此时我感到非常沮丧 我以前使用过 MySQL 所以我对一般数据库概念以及客户端 服务器模型等很满意 我从两个用户开始 root 和 sam 我 作为 sam 我使用
  • 上传文件 WCF Web API 端点

    有没有办法将文件上传到 WCF Web API 端点 如果是这样 我如何访问 Network Stream 来读取数据 很感谢任何形式的帮助 Thanks 假设您正在谈论客户端 一种方法是创建一个派生自 HttpContent 的 File
  • Flutter :已处置的 CameraController,在已处置的 CameraController 上调用了 buildPreview()

    如何正确初始化和处理相机控制器 我在用camera 0 9 4 5 与许多人一起 其他错误 https stackoverflow com questions 70592464 flutter change the path of reco