如何修复错误:类型 'Null' 不是类型 '() => void' 的子类型

Posted

技术标签:

【中文标题】如何修复错误:类型 \'Null\' 不是类型 \'() => void\' 的子类型【英文标题】:How to fix error: type 'Null' is not a subtype of type '() => void'如何修复错误:类型 'Null' 不是类型 '() => void' 的子类型 【发布时间】:2022-01-20 16:01:54 【问题描述】:

我有一个管理员登录页面,管理员可以在其中添加 ID 和密码以访问管理区域。 Firebase 数据库中有一个管理员集合,用于存储 ID 和密码。管理员集合与用户登录页面分开,并且与在允许访问之前使用 Firebase 身份验证的用户集合分开。用户访问继续正常工作。当我填写管理员登录屏幕上的两个输入框并单击按钮以获取访问权限时,我的错误对话框消息出现,表明即使有数据,两个输入字段中也没有任何数据。如果我对代码什么都不做,然后热重载并再次单击该按钮,我可以访问管理员,但我在控制台中收到以下错误消息。

在构建 ShoppingAdminSignInPage(脏,依赖项:[_LocalizationsScope-[GlobalKey#2c797]],状态:_ShoppingAdminSignInPageState#e3b3d)时引发了以下 _TypeError: 'Null' 类型不是 '() => void' 类型的子类型

我显然在我的代码中写错了一些或几件事。似乎错误出现在 ShoppingAdminSignInButton 中。提前感谢您的帮助。

class ShoppingAdminSignInPage extends StatefulWidget 
  const ShoppingAdminSignInPage(Key? key) : super(key: key);

  @override
  State<ShoppingAdminSignInPage> createState() =>
      _ShoppingAdminSignInPageState();


class _ShoppingAdminSignInPageState extends State<ShoppingAdminSignInPage> 
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final TextEditingController _adminIDController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) 
    return AdaptiveLayoutScaffold(
      appBar: const ShoppingAdminSignInPageAppBar(),
      landscapeBodyWidget: Container(),
      portraitBodyWidget: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            children: [
              const ShoppingAdminSignInHeader(),
              Form(
                key: _formKey,
                child: Column(
                  children: [
                    const SizedBox(
                      height: 50.0,
                    ),
                    AdminSignInTextField(
                      controller: _adminIDController,
                      labelText: TextFieldLabel.adminID,
                      prefixIcon: Icons.person,
                      textInputAction: TextInputAction.next,
                    ),
                    AdminSignInTextField(
                      controller: _passwordController,
                      labelText: TextFieldLabel.password,
                      prefixIcon: Icons.password,
                      textInputAction: TextInputAction.done,
                    ),
                    ShoppingAdminSignInButton(
                      onPressed: _adminIDController.text.isNotEmpty &&
                              _passwordController.text.isNotEmpty
                          ? logInAdmin()
                          : () => showDialog(
                              context: context,
                              builder: (ctx) 
                                return const ErrorAlertDialog(
                                  message: DialogString.addAdminIDAndPassword,
                                );
                              ),
                    ),
                    const NotAnAdminButton(),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  

  logInAdmin() 
    FirebaseFirestore.instance.collection('admins').get().then((snapshot) 
      snapshot.docs.forEach((result) 
        if (result.data()['id'] != _adminIDController.text.trim()) 
          SnackBarUtil.showSnackBar(
            context,
            SnackBarString.idNotCorrect,
          );
         else if (result.data()['password'] !=
            _passwordController.text.trim()) 
          SnackBarUtil.showSnackBar(
            context,
            SnackBarString.passwordNotCorrect,
          );
         else 
          SnackBarUtil.showSnackBar(
            context,
            'Welcome $result.data()['name']',
          );
          setState(() 
            _adminIDController.text = '';
            _passwordController.text = '';
          );
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(
              builder: (context) => const UploadItemsPage(),
            ),
          );
        
      );
    );
  

【问题讨论】:

【参考方案1】:
onPressed: _adminIDController.text.isNotEmpty && _passwordController.text.isNotEmpty
  ? logInAdmin()
  : () => showDialog(

上面,您所说的是如果条件为真(在这种情况下,条件为_adminIDController_passwordController 不为空)那么它应该运行logInAdmin 并等待它完成然后运行 logInAdmin 返回的任何内容。

Dart 认为logInAdmin 将返回一个函数,它应该运行该函数。不是这样的,你要按钮直接运行logInAdmin

要解决此问题,请删除括号:

onPressed: _adminIDController.text.isNotEmpty && _passwordController.text.isNotEmpty
  ? logInAdmin
  : () => showDialog(

这样,您不是在分配函数的结果,而是在分配函数本身。

同样作为一般建议,您应该始终在函数上声明返回类型,以便 dart 可以在发生这种情况时告诉您

void logInAdmin() 
  ...

【讨论】:

感谢您的快速回复。你的回答是有道理的,虽然我自己不会想出来。我更新了代码以删除括号并在 LogInAdmin 方法前面添加 void。我的代码也一定有其他问题,因为即使在更改之后,它也只有在我点击热重启后才有效。这很奇怪。但至少现在控制台中没有任何错误消息。 @h8moss @CarletonY 对不起,你能说得更具体点吗?什么只有在你点击热重启后才有效?是三元吗?如果是,您介意在文本字段的 onChanged 方法上添加 setState(() ); 并查看是否有问题吗? 无需抱歉@h8moss。我使用您非常详细的答案来重新思考问题,修复错误,然后我以一切正常的方式重写了代码。热重启、三元或其他任何东西都没有问题。再次感谢您的大力帮助。 @CarletonY 我明白了,很高兴为您提供帮助!

以上是关于如何修复错误:类型 'Null' 不是类型 '() => void' 的子类型的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 grant_type 错误为 NULL - 使用 Pay Pal 的 REST API 访问令牌不受支持的授权类型

如何修复此错误未处理的异常:类型“字符串”不是“索引”类型“int”的子类型

如何修复 Future<dynamic> 不是 Flutter 中类型的子类型

如何修复此错误类型“_InternalLinkedHashMap<String, dynamic>”不是“FutureOr<List<dynamic>>”类型的子类

使用前向声明时如何修复“字段类型不完整”错误

如何修复“XLRDError:ZIP 文件内容不是已知类型的工作簿”