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

Flutter中showDialog内调用Navigator.push报找不到Provider<UserProvider>错误

错误触发原因

核心为BuildContext的作用域不匹配,具体逻辑如下:

  • 页面按钮点击时调用Navigator.push使用的是当前页面的context,该上下文处于UserProvider的注册作用域内,跳转生成的新页面可以通过该上下文正常访问到上层的UserProvider。
  • showDialog生成的弹窗是Navigator维护的独立路由层,showDialog的builder回调传入的context是弹窗专属的路由上下文,不在原有UserProvider的作用域范围内。你在弹窗点击事件中直接使用该弹窗上下文执行跳转,新页面的祖先链路中不存在UserProvider,因此触发找不到Provider的错误。
解决方案

以下三种方案按需选择即可:

方案1:调整context引用(最便捷,无需调整Provider注册逻辑)

重命名showDialog的builder参数的上下文变量名,避免覆盖父页面的context,跳转时使用父页面的上下文,关闭弹窗时使用弹窗自身的上下文即可,修改后的代码参考:

query_popup() {      
    return showDialog(
      context: context, // 此处用的是父页面的context
      // 将builder的参数重命名为dialogContext,避免和父级context重名冲突
      builder: (BuildContext dialogContext) {
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(Radius.circular(8.0)),
          ),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Container(height: 5.0),
              Text("End & save?"),
              Container(height: 20.0),
              InkWell(
                onTap: () {
                  // 跳转时使用父页面的context,保证Provider作用域正常
                  Navigator.push(context,MaterialPageRoute(builder: (context) => TabbarScreen(SelectedPage: 0)),);
                },
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Container(width: 10.0, height: 40.0),
                    Text('Yes'),
                  ],
                ),
              ),
              Container(height: 5.0),
              InkWell(
                onTap: () {
                  // 关闭弹窗用弹窗自身的context
                  Navigator.pop(dialogContext);
                },
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Container(width: 20.0, height: 40.0),
                    Text('No')
                  ],
                ),
              ),
            ],
          ),
        );
      },
    );
}

方案2:提升Provider注册层级(适合全局使用的Provider)

如果UserProvider是你整个应用都需要用到的全局状态,直接将它的注册逻辑提升到MaterialApp的父层级,这样所有路由(包括弹窗、新打开的页面)都可以正常访问到该Provider:

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => UserProvider(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // 原有应用配置不变
    );
  }
}

方案3:向弹窗透传Provider(适合弹窗内部需要直接访问Provider的场景)

如果你的弹窗内部逻辑本身也需要使用UserProvider,可以在弹窗的builder中将父级的Provider透传到弹窗的组件树内:

query_popup() {      
    return showDialog(
      context: context,
      builder: (BuildContext context) {
        return ChangeNotifierProvider.value(
          // 透传父级的UserProvider
          value: Provider.of<UserProvider>(context, listen: false),
          child: AlertDialog(
            // 原有弹窗内容不变
          ),
        );
      },
    );
}

内容的提问来源于stack exchange,提问作者Bernhard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 19:54:05