由于VS代码无法识别我的手机,因此我尝试使用相机插件拍摄视频,并且在Xcode
中运行项目以运行真实设备时。
问题是,即使我打电话给dispose()
,应用程序崩溃,我也将摄像机前后切换到5次以上(少于10次)。另外,在录制视频和播放录制的视频时,几乎会发生50%到60%的崩溃。
Xcode说
来自调试器的消息:由于内存问题而终止
我看到flutter没有任何内存泄漏,我们也不需要关心内存管理。
那为什么会这样呢?
我缺少什么东西吗?
有人知道发生了什么吗?
代码:
class CameraScreenState extends State<CameraScreen>
with TickerProviderStateMixin {
List<CameraDescription> _cameraDescriptions;
CameraController _cameraController;
VideoPlayerController _videoController;
AnimationController _animationController;
String imagePath;
String videoPath;
VoidCallback videoPlayerListener;
bool _isSelfie = false;
bool _isRecorded = false;
bool _isRecording = false;
bool _isReady = false;
@override
void initState() {
super.initState();
_setupCameras();
}
Future<void> _setupCameras() async {
try {
_cameraDescriptions = await availableCameras();
_cameraController = new CameraController(_cameraDescriptions[0], ResolutionPreset.high);
await _cameraController.initialize();
} on CameraException catch (_) {
// do something on error.
}
if (!mounted) return;
setState(() {
_isReady = true;
});
_animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 15),
);
}
@override
void deactivate() {
_videoController?.setVolume(0.0);
_videoController?.removeListener(videoPlayerListener);
super.deactivate();
}
@override
void dispose() {
_cameraController?.dispose();
_animationController?.dispose();
_videoController?.dispose();
super.dispose();
}
String timestamp() => new DateTime.now().millisecondsSinceEpoch.toString();
Future _changeDirection(CameraDescription cameraDescription) async {
await _cameraController.dispose().then((_) async {
_cameraController =
new CameraController(cameraDescription, ResolutionPreset.high);
_cameraController.addListener(() {
if (mounted) setState(() {});
if (_cameraController.value.hasError) {
print(_cameraController.value.errorDescription);
}
});
try {
await _cameraController.initialize();
} on CameraException catch (e) {
print(e);
}
if (mounted) {
setState(() {});
}
});
}
_toSelfie() {
_changeDirection(_cameraDescriptions[1]);
}
_toForward() {
_changeDirection(_cameraDescriptions[0]);
}
void onVideoRecordButtonPressed() {
startVideoRecording().then((String filePath) {
if (mounted) setState(() {});
if (filePath != null) print('Saving video to $filePath');
});
}
void onStopButtonPressed() {
stopVideoRecording().then((_) {
if (mounted) setState(() {});
print('Video recorded to: $videoPath');
});
}
Future<String> startVideoRecording() async {
if (!_cameraController.value.isInitialized) {
print('Error: select a camera first.');
return null;
}
final Directory extDir = await getTemporaryDirectory();
final String dirPath = '${extDir.path}/Movies/flutter_test';
await new Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.mp4';
if (_cameraController.value.isRecordingVideo) {
// A recording is already started, do nothing.
return null;
}
try {
videoPath = filePath;
await _cameraController.startVideoRecording(filePath).then((_) async {
final animation = _animationController.forward(from: 0.0);
await animation.then((_) {
setState(() {
onStopButtonPressed();
_isRecorded = true;
});
});
});
} on CameraException catch (e) {
print(e);
return null;
}
return filePath;
}
Future<void> stopVideoRecording() async {
if (!_cameraController.value.isRecordingVideo) {
return null;
}
try {
await _cameraController.stopVideoRecording();
} on CameraException catch (e) {
print(e);
return null;
}
await _startVideoPlayer();
}
Future<void> _startVideoPlayer() async {
final VideoPlayerController vcontroller =
new VideoPlayerController.file(new File(videoPath));
videoPlayerListener = () {
if (_videoController != null && _videoController.value.size != null) {
// Refreshing the state to update video player with the correct ratio.
if (mounted) setState(() {});
_videoController.removeListener(videoPlayerListener);
}
};
vcontroller.addListener(videoPlayerListener);
await vcontroller.setLooping(true);
await vcontroller.initialize();
await _videoController?.dispose();
if (mounted) {
setState(() {
imagePath = null;
_videoController = vcontroller;
});
}
await vcontroller.play();
}
_startVideoRecordingCoountDown() {
onVideoRecordButtonPressed();
}
_stopVideoRecordingCountDown() {
setState(() {
_animationController.stop();
onStopButtonPressed();
_isRecorded = true;
});
}
@override
Widget build(BuildContext context) {
if (!_isReady) {
return new Container(
color: Colors.black,
child: new Center(child: new CircularProgressIndicator()));
}
return new Scaffold(
backgroundColor: Colors.black,
body: !_isRecorded
? new Stack(
children: <Widget>[
new AspectRatio(
aspectRatio: _cameraController.value.aspectRatio,
child: new CameraPreview(_cameraController),
),
!_isRecording
? new Align(
alignment: Alignment.topLeft,
child: new Container(
child: new FloatingActionButton(
heroTag: 'start',
backgroundColor: Colors.black.withOpacity(0.001),
elevation: 50.0,
child: new Center(
child: new Icon(Icons.clear, size: 28.0)),
onPressed: () {
Navigator.of(context).pop();
},
),
),
)
: new Container(),
new Align(
alignment: new Alignment(0.0, 1.0),
child: new Container(
margin: const EdgeInsets.only(bottom: 10.0),
child: new FloatingActionButton(
elevation: 30.0,
backgroundColor: Colors.white,
foregroundColor: Colors.amber,
child: _animationController.isAnimating
? new Countdown(
animation: new StepTween(
begin: 16,
end: 0,
).animate(_animationController),
)
: new Icon(Icons.play_arrow),
onPressed: () {
setState(() {
_isRecording = true;
});
!_animationController.isAnimating
? _startVideoRecordingCoountDown()
: _stopVideoRecordingCountDown();
},
),
),
),
!_isRecording
? new Align(
alignment: Alignment.bottomRight,
child: new Container(
margin:
const EdgeInsets.only(right: 15.0, bottom: 10.0),
child: new FloatingActionButton(
elevation: 50.0,
backgroundColor: Colors.black.withOpacity(0.001),
child: new Icon(Icons.cached, size: 35.0),
onPressed: () {
setState(() {
_isSelfie ? _toForward() : _toSelfie();
_isSelfie
? _isSelfie = false
: _isSelfie = true;
});
},
),
),
)
: new Container(),
],
fit: StackFit.expand,
)
: _videoController == null
? new Container(
color: Colors.black,
child: new Center(child: new CircularProgressIndicator()))
: _videoController.value.size != null
? new AspectRatio(
aspectRatio: _videoController.value.aspectRatio,
child: new VideoPlayer(_videoController),
)
: new Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: new VideoPlayer(_videoController)),
);
}
}