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

Flutter中使用GoRouter切换页面时如何禁用mobile_scanner组件

Flutter中使用GoRouter切换页面时如何禁用mobile_scanner组件

看起来你遇到的问题是用GoRouter的StatefulShellRoute做底部导航时,切换页面后QR扫描器还在后台偷偷运行对吧?我之前也碰到过类似的情况,其实核心问题是StatefulShellRoute的各个分支页面切换时,原来的页面并没有被销毁,只是被隐藏了,所以你尝试的onExit方法根本不会触发(因为路由没被弹出)。下面给你几个靠谱的解决思路:

方法一:利用RouteAware监听页面可见性(最推荐)

这是Flutter官方推荐的监听路由可见性变化的方式,刚好适配你这种页面隐藏/显示的场景:

  1. 给QR页面的State混入RouteAware
    首先你的QR页面得是StatefulWidget,然后在State类中混入RouteAware,通过路由的生命周期回调来控制扫描器的启停:

    class QRPageState extends State<QRPage> with RouteAware {
      late MobileScannerController _scannerController;
    
      @override
      void initState() {
        super.initState();
        _scannerController = MobileScannerController();
        // 初始化时先不启动扫描,等页面可见后再启动
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        // 注册RouteObserver,需要在根App中提前配置全局实例
        final routeObserver = Router.of(context).routeObserver as RouteObserver<PageRoute>;
        routeObserver.subscribe(this, ModalRoute.of(context)! as PageRoute);
      }
    
      @override
      void dispose() {
        // 取消注册+销毁扫描控制器,避免内存泄漏
        final routeObserver = Router.of(context).routeObserver as RouteObserver<PageRoute>;
        routeObserver.unsubscribe(this);
        _scannerController.dispose();
        super.dispose();
      }
    
      // 页面首次被推到前台时启动扫描
      @override
      void didPush() {
        super.didPush();
        _scannerController.start();
      }
    
      // 从其他页面返回当前页面时重启扫描
      @override
      void didPopNext() {
        super.didPopNext();
        _scannerController.start();
      }
    
      // 当前页面被隐藏(切换到其他底部导航页面)时停止扫描
      @override
      void didPushNext() {
        super.didPushNext();
        _scannerController.stop();
      }
    
      // 页面被弹出时停止扫描
      @override
      void didPop() {
        super.didPop();
        _scannerController.stop();
      }
    
      @override
      Widget build(BuildContext context) {
        return MobileScanner(
          controller: _scannerController,
          // 其他扫描器配置...
        );
      }
    }
    
  2. 在根App中配置全局RouteObserver
    你需要在项目的根MaterialApp(或CupertinoApp)中提供一个RouteObserver实例,这样页面才能订阅路由变化:

    final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp.router(
          routerConfig: _router,
          routeObserver: routeObserver,
          // 其他App配置...
        );
      }
    }
    

方法二:利用WidgetsBindingObserver监听页面可见性(适合简单场景)

如果你觉得RouteAware配置有点麻烦,也可以用WidgetsBindingObserver来监听APP的可见性状态。不过要注意,这个是监听整个APP的前后台变化,虽然在APP前台切换页面时也能触发,但精准度不如RouteAware:

class QRPageState extends State<QRPage> with WidgetsBindingObserver {
  late MobileScannerController _scannerController;

  @override
  void initState() {
    super.initState();
    _scannerController = MobileScannerController();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _scannerController.dispose();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    switch (state) {
      case AppLifecycleState.resumed:
        // 页面回到前台时启动扫描
        _scannerController.start();
        break;
      case AppLifecycleState.paused:
      case AppLifecycleState.inactive:
      case AppLifecycleState.detached:
        // 页面被隐藏时停止扫描
        _scannerController.stop();
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MobileScanner(
      controller: _scannerController,
      // 其他扫描器配置...
    );
  }
}

为什么onExit方法没用?

这里给你补个知识点:你之前尝试的onExit回调只有在路由被弹出(比如用户按返回键、调用context.pop())的时候才会触发,但用StatefulShellRoute切换底部导航栏时,QR页面所在的路由并没有被弹出,只是被当前活跃的分支导航器隐藏了,所以onExit根本不会执行,自然也就没法调用到页面的方法啦。

不管用哪种方法,一定要在页面的dispose方法中停止并销毁MobileScannerController,不然会导致内存泄漏,甚至相机权限的遗留问题。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:19:56