Flutter Camera录制视频前UI卡顿冻结,如何解决?
解决Flutter相机录制前UI卡顿问题
问题描述
我是Flutter新手,正在开发一款相机录视频应用。实现代码后,点击录制按钮前UI会卡顿冻结约半秒,尝试将prepareForVideoRecording调用提前到相机控制器初始化后执行,问题仍未解决。以下是我的代码:
import 'dart:io'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class CameraPage extends StatefulWidget { const CameraPage({Key? key}) : super(key: key); @override _CameraPageState createState() => _CameraPageState(); } class _CameraPageState extends State<CameraPage> { bool _isLoading = true; bool _isRecording = false; late CameraController _cameraController; @override void initState() { super.initState(); _initCamera(); } @override void dispose() { _cameraController.dispose(); super.dispose(); } Future<void> _initCamera() async { final cameras = await availableCameras(); final front = cameras.firstWhere( (camera) => camera.lensDirection == CameraLensDirection.front); _cameraController = CameraController(front, ResolutionPreset.max); await _cameraController.initialize(); setState(() => _isLoading = false); } Future<void> _recordVideo() async { if (_isRecording) { final file = await _cameraController.stopVideoRecording(); setState(() => _isRecording = false); final route = MaterialPageRoute( fullscreenDialog: true, builder: (_) => VideoPage(filePath: file.path), ); Navigator.push(context, route); } else { await _cameraController.prepareForVideoRecording(); await _cameraController.startVideoRecording(); setState(() => _isRecording = true); } } @override Widget build(BuildContext context) { if (_isLoading) { return Container( color: Colors.white, child: const Center( child: CircularProgressIndicator(), ), ); } else { return Center( child: Stack( alignment: Alignment.bottomCenter, children: [ CameraPreview(_cameraController), Padding( padding: const EdgeInsets.all(25), child: FloatingActionButton( backgroundColor: Colors.red, child: Icon(_isRecording ? Icons.stop : Icons.circle), onPressed: () => _recordVideo(), ), ), ], ), ); } } } class VideoPage extends StatefulWidget { final String filePath; const VideoPage({Key? key, required this.filePath}) : super(key: key); @override _VideoPageState createState() => _VideoPageState(); } class _VideoPageState extends State<VideoPage> { late VideoPlayerController _videoPlayerController; @override void dispose() { _videoPlayerController.dispose(); super.dispose(); } Future _initVideoPlayer() async { _videoPlayerController = VideoPlayerController.file(File(widget.filePath)); await _videoPlayerController.initialize(); await _videoPlayerController.setLooping(true); await _videoPlayerController.play(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Preview'), elevation: 0, backgroundColor: Colors.black26, actions: [ IconButton( icon: const Icon(Icons.check), onPressed: () { print('do something with the file'); }, ) ], ), extendBodyBehindAppBar: true, body: FutureBuilder( future: _initVideoPlayer(), builder: (context, state) { if (state.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else { return VideoPlayer(_videoPlayerController); } }, ), ); } }
解决方案
1. 提前完成录制准备,避免UI线程阻塞
在相机初始化完成后,立即调用prepareForVideoRecording,并用Future.microtask确保操作在UI渲染后执行,不阻塞初始界面加载:
Future<void> _initCamera() async { final cameras = await availableCameras(); final front = cameras.firstWhere( (camera) => camera.lensDirection == CameraLensDirection.front); _cameraController = CameraController(front, ResolutionPreset.max); await _cameraController.initialize(); // 提前在后台完成录制准备,不阻塞UI await Future.microtask(() => _cameraController.prepareForVideoRecording()); setState(() => _isLoading = false); }
2. 优化录制按钮点击逻辑,先更新UI再执行操作
点击录制时,先更新_isRecording状态刷新UI,再执行录制相关操作,避免UI等待耗时操作完成:
Future<void> _recordVideo() async { if (_isRecording) { // 先更新UI状态,再执行停止录制 setState(() => _isRecording = false); final file = await _cameraController.stopVideoRecording(); final route = MaterialPageRoute( fullscreenDialog: true, builder: (_) => VideoPage(filePath: file.path), ); Navigator.push(context, route); } else { // 先切换录制状态,再启动录制(已提前准备) setState(() => _isRecording = true); await _cameraController.startVideoRecording(); } }
3. 修复视频预览页面的异步操作问题
将视频初始化逻辑移至initState,避免每次build时重复执行异步操作,减少额外卡顿:
class _VideoPageState extends State<VideoPage> { late VideoPlayerController _videoPlayerController; bool _isVideoReady = false; @override void initState() { super.initState(); _initVideoPlayer(); } Future _initVideoPlayer() async { _videoPlayerController = VideoPlayerController.file(File(widget.filePath)); await _videoPlayerController.initialize(); await _videoPlayerController.setLooping(true); await _videoPlayerController.play(); setState(() => _isVideoReady = true); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Preview'), elevation: 0, backgroundColor: Colors.black26, actions: [ IconButton( icon: const Icon(Icons.check), onPressed: () { print('do something with the file'); }, ) ], ), extendBodyBehindAppBar: true, body: _isVideoReady ? VideoPlayer(_videoPlayerController) : const Center(child: CircularProgressIndicator()), ); } }
内容的提问来源于stack exchange,提问作者New Tos
相关产品推荐
相关产品推荐

