You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何在Riverpod Provider中监听GoRouter路由/位置变化?

解决方案

要实现相机在页面被堆叠时释放资源,核心是让相机的生命周期和路由状态联动。你之前的两种方法失效的原因分别是:

  • GoRoute的builder不会在子路由跳转时重新触发,因为父路由Widget仍保留在栈中;
  • redirect方法属于路由解析阶段,不允许在此修改Provider状态,会触发框架异常。

下面提供两种可行的实现方式:

方式一:用Riverpod Notifier监听路由状态管理相机

这种方式把相机的生命周期完全交给Riverpod管理,通过监听GoRouter的位置变化自动控制相机启停:

  1. 定义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;
    }
  }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 21:55:45