diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index 3af291afe63b..0b870fe4431d 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -4,10 +4,11 @@ import 'dart:async'; import 'dart:io'; -import 'dart:ui'; +import 'dart:ui' as ui; import 'package:camera/camera.dart'; -import 'package:flutter/painting.dart'; +import 'package:camera_example/main.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider/path_provider.dart'; import 'package:video_player/video_player.dart'; @@ -63,7 +64,9 @@ void main() { // Load picture final File fileImage = File(file.path); - final Image image = await decodeImageFromList(fileImage.readAsBytesSync()); + final ui.Image image = await decodeImageFromList( + fileImage.readAsBytesSync(), + ); // Verify image dimensions are as expected expect(image, isNotNull); @@ -292,4 +295,28 @@ void main() { }, skip: !Platform.isIOS, ); + + testWidgets( + 'Disposed controller removed correctly', + (WidgetTester tester) async { + cameras = await availableCameras(); + if (cameras.isEmpty) { + return; + } + + // Bump the example. + await tester.pumpWidget(CameraApp()); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + // Tap to switch to the first camera. + await tester.tap( + find.byIcon(getCameraLensIcon(cameras.first.lensDirection)), + ); + // Wait a few seconds to make sure the lifecycle changed. + await tester.pumpAndSettle(const Duration(seconds: 3)); + // Ensure the controller is no longer depended by widgets. + final dynamic exception = tester.takeException(); + expect(exception, isNull); + }, + ); } diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index a3a5d1d46391..74dbae9fd169 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -626,7 +626,12 @@ class _CameraExampleHomeState extends State void onNewCameraSelected(CameraDescription cameraDescription) async { if (controller != null) { - await controller!.dispose(); + CameraController? _controller = controller!; + setState(() { + controller = null; + }); + await _controller.dispose(); + _controller = null; } final CameraController cameraController = CameraController( @@ -636,8 +641,6 @@ class _CameraExampleHomeState extends State imageFormatGroup: ImageFormatGroup.jpeg, ); - controller = cameraController; - // If the controller is updated then update the UI. cameraController.addListener(() { if (mounted) setState(() {}); @@ -668,6 +671,7 @@ class _CameraExampleHomeState extends State .getMinZoomLevel() .then((value) => _minAvailableZoom = value), ]); + controller = cameraController; } on CameraException catch (e) { _showCameraException(e); }