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
相关产品推荐
相关产品推荐

