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

Flutter中使用Provider监听Job类Timestamp变化以更新表格行

解决Job类timestamp变化时UI不更新的问题

问题根源

你当前在JobDetailsScreen中通过Provider.of<Jobs>(context).findById(jobId)获取Job实例,但这个Widget仅监听Jobs类的变化。当单个Job内部调用notifyListeners()时,Jobs并未触发通知,导致Widget不会重新构建,表格行也就无法更新。

解决方案

让JobDetailsScreen直接监听目标Job实例的变化,同时修复代码中的小问题:

1. 用ListenableBuilder监听Job实例变化

在表格部分包裹ListenableBuilder,这样Job内部数据变化时,只会重建表格区域,性能更优:

// 修改job_details.dart中的body部分
body: Container(
  child: Column(
    children: [
      Row(
        children: [
          // 保留原有的Start/Stop按钮代码
        ],
      ),
      // 用ListenableBuilder包裹表格
      ListenableBuilder(
        listenable: loadedJob,
        builder: (context, child) {
          return Table(
            children: createTimeStampTable(loadedJob.timestamps),
          );
        },
      ),
    ],
  ),
),

2. 修复Job类中的逻辑错误

Job类的toggleIsCompleted方法存在赋值错误,修正为:

void toggleIsCompleted(){
  isCompleted = !isCompleted; // 原代码未正确修改isCompleted的值
  notifyListeners();
}

3. 修复AlertDialog的显示问题

原代码中直接创建AlertDialog但未调用showDialog,导致弹窗无法弹出,修正按钮的异常处理逻辑:

// 以Start按钮为例
TextButton(
  onPressed: () {
    try {
      loadedJob.addStartTime();
    } on Exception catch (e) {
      showDialog(
        context: context,
        builder: (ctx) => AlertDialog(
          title: Text(e.toString()),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(ctx).pop(),
              child: Container(
                color: Colors.green,
                padding: const EdgeInsets.all(14),
                child: const Text("okay"),
              ),
            ),
          ],
        ),
      );
    }
  },
  child: const Text("Start"),
),

完整修改后的JobDetailsScreen核心代码

@override
Widget build(BuildContext context) {
  final jobId = ModalRoute.of(context)?.settings.arguments as int;
  final loadedJob = Provider.of<Jobs>(context).findById(jobId);

  List<TableRow> createTimeStampTable(List<Map<String, DateTime?>> items) {
    List<TableRow> itemProperties = [];
    itemProperties.add(const TableRow(children: [
      TableCell(child: Text("Start Time")),
      TableCell(child: Text("End Time"))
    ]));
    for (int i = 0; i < items.length; ++i) {
      itemProperties.add(TableRow(children: [
        TableCell(child: Text("${items[i]["startTime"]?.hour}:${items[i]["startTime"]?.minute}")),
        TableCell(child: Text("${items[i]["endTime"]?.hour}:${items[i]["endTime"]?.minute}")),
      ]));
    }
    return itemProperties;
  }

  return Scaffold(
    appBar: AppBar(title: Text(loadedJob.name)),
    body: Container(
      child: Column(
        children: [
          Row(
            children: [
              TextButton(
                onPressed: () {
                  try {
                    loadedJob.addStartTime();
                  } on Exception catch (e) {
                    showDialog(
                      context: context,
                      builder: (ctx) => AlertDialog(
                        title: Text(e.toString()),
                        actions: [
                          TextButton(
                            onPressed: () => Navigator.of(ctx).pop(),
                            child: Container(
                              color: Colors.green,
                              padding: const EdgeInsets.all(14),
                              child: const Text("okay"),
                            ),
                          ),
                        ],
                      ),
                    );
                  }
                },
                child: const Text("Start"),
              ),
              TextButton(
                onPressed: () {
                  try {
                    loadedJob.addEndTime();
                  } on Exception catch (e) {
                    showDialog(
                      context: context,
                      builder: (ctx) => AlertDialog(
                        title: Text(e.toString()),
                        actions: [
                          TextButton(
                            onPressed: () => Navigator.of(ctx).pop(),
                            child: Container(
                              color: Colors.green,
                              padding: const EdgeInsets.all(14),
                              child: const Text("okay"),
                            ),
                          ),
                        ],
                      ),
                    );
                  }
                },
                child: const Text("Stop"),
              ),
            ],
          ),
          ListenableBuilder(
            listenable: loadedJob,
            builder: (context, _) {
              return Table(
                children: createTimeStampTable(loadedJob.timestamps),
              );
            },
          ),
        ],
      ),
    ),
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:24:55