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

Flutter Provider使用报错:闭包参数不匹配及构建时状态更新异常

Flutter Provider开发遇到两类异常的排查与解决

首次使用Provider开发Flutter应用时出现两类异常:

  • 构建期间调用setState()或markNeedsBuild()的断言错误
  • 闭包调用参数不匹配的NoSuchMethodError

报错信息

异常1:构建期间调用更新方法

======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for TaskData:
setState() or markNeedsBuild() called during build.

This _InheritedProviderScope<TaskData?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<TaskData?>
  value: Instance of 'TaskData'
  listening to value
The widget which was currently being built when the offending call was made was: TaskTile
  dirty
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4862:9)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4874:6)
#2      _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:577:5)
#3      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:403:24)

异常2:闭包参数不匹配

======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building TaskTile(dirty):
Closure call with mismatched arguments: function 'TasksList.build.<anonymous closure>.<anonymous closure>.<anonymous closure>'
Receiver: Closure: (dynamic) => Null
Tried calling: TasksList.build.<anonymous closure>.<anonymous closure>.<anonymous closure>()
Found: TasksList.build.<anonymous closure>.<anonymous closure>.<anonymous closure>(dynamic) => Null

The relevant error-causing widget was: 
  TaskTile TaskTile:file:///D:/Development/VS%20Code%20flutter/todoey_app/lib/widgets/tasks_list.dart:15:20
When the exception was thrown, this was the stack: 
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)
#1      _objectNoSuchMethod (dart:core-patch/object_patch.dart:85:9)
#2      TaskTile.build (package:todoey_app/widgets/task_tile.dart:27:36)
#3      StatelessElement.build (package:flutter/src/widgets/framework.dart:5367:49)
#4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5297:15)
#5      Element.rebuild (package:flutter/src/widgets/framework.dart:5016:7)
#6      StatelessElement.update (package:flutter/src/widgets/framework.dart:5373:5)
#7      Element.updateChild (package:flutter/src/widgets/framework.dart:3685:15)
#8      SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6441:14)
#9      Element.updateChild (package:flutter/src/widgets/framework.dart:3685:15)
#10     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6441:14)
#11     Element.updateChild (package:flutter/src/widgets/framework.dart:3685:15)
#12     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5322:16)
#13     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5462:11)

相关代码

TasksList组件

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todoey_app/widgets/task_tile.dart';
import '../models/task_data.dart';

class TasksList extends StatelessWidget {
  const TasksList({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Consumer<TaskData>(
      builder: (context, taskData, child) {
        return ListView.builder(
          itemBuilder: (context, index) {
            final task = taskData.tasks[index];
            return TaskTile(
              taskTitle: task.name,
              isChecked: task.isDone,
              checkboxCallback: (checkboxState) {
                taskData.updateTask(task);
              },
              longPressCallback: () {
                taskData.deleteTask(task);
              },
            );
          },
          itemCount: taskData.taskCount,
        );
      },
    );
  }
}

TaskTile组件

import 'package:flutter/material.dart';

class TaskTile extends StatelessWidget {
  final bool isChecked;
  final String taskTitle;
  final Function checkboxCallback;
  final Function longPressCallback;

  TaskTile(
      {required this.isChecked,
      required this.taskTitle,
      required this.checkboxCallback,
      required this.longPressCallback});

  @override
  Widget build(BuildContext context) {
    return ListTile(
      onLongPress: longPressCallback(),
      title: Text(
        taskTitle,
        style: TextStyle(
            decoration: isChecked ? TextDecoration.lineThrough : null),
      ),
      trailing: Checkbox(
        activeColor: Colors.lightBlueAccent,
        value: isChecked,
        onChanged: checkboxCallback(),
      ),
    );
  }
}

问题原因与解决方案

核心问题

两个异常的根源都在于TaskTile组件中错误地直接执行了回调函数,而非传递函数引用:

  1. longPressCallback()和checkboxCallback()在组件build阶段就被调用,触发taskData.updateTask()/taskData.deleteTask(),进而调用notifyListeners()——此时组件仍在构建流程中,导致框架抛出“构建期间调用更新方法”的断言错误。
  2. checkboxCallback定义为接收参数的闭包,但调用时未传入参数,引发“闭包参数不匹配”的NoSuchMethodError。

修复后的TaskTile代码

import 'package:flutter/material.dart';

class TaskTile extends StatelessWidget {
  final bool isChecked;
  final String taskTitle;
  final Function(bool?) checkboxCallback; // 明确参数类型为bool?,匹配Checkbox的onChanged回调
  final VoidCallback longPressCallback; // 长按回调无参数,使用VoidCallback更规范

  TaskTile({
    required this.isChecked,
    required this.taskTitle,
    required this.checkboxCallback,
    required this.longPressCallback,
  });

  @override
  Widget build(BuildContext context) {
    return ListTile(
      onLongPress: longPressCallback, // 传递函数引用,不执行
      title: Text(
        taskTitle,
        style: TextStyle(
          decoration: isChecked ? TextDecoration.lineThrough : null,
        ),
      ),
      trailing: Checkbox(
        activeColor: Colors.lightBlueAccent,
        value: isChecked,
        onChanged: checkboxCallback, // 传递函数引用,参数自动匹配
      ),
    );
  }
}

修复说明

  • 移除回调后的(),改为直接传递函数引用,确保只有用户触发对应操作(长按/点击复选框)时才执行回调,避免在build阶段调用更新方法。
  • 明确回调函数的参数类型:checkboxCallback指定为Function(bool?),匹配Checkbox.onChanged的参数类型;longPressCallback使用VoidCallback(无参无返回值的函数类型),代码更规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 23:27:09