Flutter:如何在Riverpod Provider中监听GoRouter路由/位置变化?
解决方案
要实现相机在页面被堆叠时释放资源,核心是让相机的生命周期和路由状态联动。你之前的两种方法失效的原因分别是:
- GoRoute的builder不会在子路由跳转时重新触发,因为父路由Widget仍保留在栈中;
- redirect方法属于路由解析阶段,不允许在此修改Provider状态,会触发框架异常。
下面提供两种可行的实现方式:
方式一:用Riverpod Notifier监听路由状态管理相机
这种方式把相机的生命周期完全交给Riverpod管理,通过监听GoRouter的位置变化自动控制相机启停:
- 定义GoRouter的Provider和相机管理的Notifier:
import 'package:riverpod/riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:camera/camera.dart'; // 提供GoRouter实例 final goRouterProvider = Provider<GoRouter>((ref) { return GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const CameraWidget(), routes: [ GoRoute( path: 'page1', builder: (context, state) => const Page1Screen(), ), ], ), ], ); }); // 相机控制器的Notifier,负责初始化和释放 final cameraControllerProvider = NotifierProvider<CameraControllerNotifier, CameraController?>((ref) { return CameraControllerNotifier(ref); }); class CameraControllerNotifier extends Notifier<CameraController?> { late Ref _ref; @override CameraController? build() { _ref = ref; // 监听GoRouter的位置变化,自动重建状态 final currentLocation = _ref.watch(goRouterProvider.select((router) => router.location)); if (currentLocation == '/') { // 替换成你的相机初始化逻辑,比如获取相机列表后选择第一个 return CameraController( // 这里需要传入实际的CameraDescription const CameraDescription( name: '', lensDirection: CameraLensDirection.back, sensorOrientation: 90, ), ResolutionPreset.high, )..initialize(); } else { // 路由离开根路径时释放相机 state?.dispose(); return null; } } }
- 在CameraWidget中使用该Provider:
class CameraWidget extends ConsumerWidget { const CameraWidget({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final cameraController = ref.watch(cameraControllerProvider); if (cameraController == null || !cameraController.value.isInitialized) { return const Center(child: Text("相机已关闭")); } return CameraPreview(cameraController); } }
方式二:在CameraWidget中直接监听路由变化
如果不想修改Provider结构,可以在CameraWidget的State类中手动监听GoRouter的路由事件:
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:camera/camera.dart'; class CameraWidget extends StatefulWidget { const CameraWidget({super.key}); @override State<CameraWidget> createState() => _CameraWidgetState(); } class _CameraWidgetState extends State<CameraWidget> { CameraController? _controller; @override void initState() { super.initState(); // 初始化相机 _initCamera(); // 添加路由监听 GoRouter.of(context).addListener(_onRouteChanged); } @override void dispose() { // 移除监听并释放相机 GoRouter.of(context).removeListener(_onRouteChanged); _controller?.dispose(); super.dispose(); } void _onRouteChanged() { final location = GoRouter.of(context).location; if (location == '/') { _initCamera(); } else { _disposeCamera(); } } Future<void> _initCamera() async { if (_controller != null) return; // 替换成你的相机初始化逻辑 final cameras = await availableCameras(); _controller = CameraController(cameras[0], ResolutionPreset.high); await _controller?.initialize(); if (mounted) setState(() {}); } void _disposeCamera() { _controller?.dispose(); _controller = null; if (mounted) setState(() {}); } @override Widget build(BuildContext context) { if (_controller == null || !_controller!.value.isInitialized) { return const Center(child: Text("相机已关闭")); } return CameraPreview(_controller!); } }
两种方式都能实现需求:当路由跳转到/page1时,相机资源被释放;回到/时重新初始化。
内容的提问来源于stack exchange,提问作者Michele
相关产品推荐
相关产品推荐

