Flutter使用GetX状态管理时ListView.builder新增数据未实时更新问题求助
问题原因&修复方案
核心问题点
- 响应式变量
items未实际使用:你在Controller中定义了items = <Word>[].obs但所有数据库操作后都没有更新这个变量,obs变量只有值发生变化时才会触发UI更新 Obx用法完全错误:Obx是用来包裹需要响应状态变化的Widget组件,不能放在点击事件回调中使用- 列表渲染逻辑错误:你用了
FutureBuilder每次渲染都重新请求数据库,没有绑定响应式变量,新增数据后自然不会自动刷新
修复步骤
第一步:修改WordController代码
class WordController extends GetxController { TextEditingController controllerInput1 = TextEditingController(); TextEditingController controllerInput2 = TextEditingController(); var items = <Word>[].obs; final translator = GoogleTranslator(); // 控制器初始化时自动拉取一次数据 @override void onInit() { super.onInit(); getir(); } ekle(Word word) async { var val = await WordRepo().add(word); showDilog("Kayıt Başarılı"); // 新增成功后刷新列表数据 await getir(); return val; } updateWord(Word word) async { var val = await WordRepo().update(word); showDilog("Kayıt Başarılı"); // 更新成功后刷新列表数据 await getir(); return val; } deleteWord(int? id) async { var val = await WordRepo().deleteById(id!); // 删除成功后刷新列表数据 await getir(); return val; } getir() async { var list = await WordRepo().getAll(); // 把数据库返回的列表赋值给响应式变量,触发UI更新 items.assignAll(list); print(list); return list; } translateLanguage(String newValue) async { if(newValue==null || newValue.length==0){ return; } List list=["I","i"]; if(newValue.length==1 && !list.contains(newValue)){ return; } var translate = await translator .translate(newValue, from: 'en', to: 'tr'); controllerInput2.text = translate.toString(); return translate; } showDilog(String message) { Get.defaultDialog(title: "Bilgi", middleText: message); } addNote() async { var word = Word(wordEn: controllerInput1.text, wordTr: controllerInput2.text); await ekle(word); clear(); } clear(){ controllerInput2.clear(); controllerInput1.clear(); } updateNote() async { var word = Word(wordEn: controllerInput1.text, wordTr: controllerInput2.text); await updateWord(word); await getir(); update(); } }
第二步:修改UI层代码
- 删除build方法中的
controller.getir()调用,已经放在Controller的onInit中自动执行了 - 替换
historyWordList的实现,删除原有FutureBuilder,改用Obx绑定响应式变量:
Widget get historyWordList { // 用Obx包裹列表,只要items变化就自动重绘 return Obx(() { if (controller.items.isEmpty) { return const Center(child: Text("暂无数据")); } return ListView.builder( itemCount: controller.items.length, itemBuilder: (context, index) { final word = controller.items[index]; return Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5.0)), ), margin: EdgeInsets.only(left: 8.0, right: 8.0, top: 0.8), child: Container( color: Colors.white30, height: 70.0, padding: EdgeInsets.only(left: 8.0, top: 8.0, bottom: 8.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text( "İngilizce: ${word.wordEn ?? ""}", style: TextStyle(fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis, ), Text( "Türkçe: ${word.wordTr ?? ""}", style: TextStyle(fontWeight: FontWeight.w400), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), historyIconbutton, ], ), ), ); }, ); }); }
- 删除
favoriIconButton的onPressed中无用的Obx代码和refreshList调用,现在addNote执行后会自动更新items触发列表刷新:
get favoriIconButton { return IconButton( alignment: Alignment.topRight, onPressed: () async { bool validatorKontrol = _formKey.currentState!.validate(); if (validatorKontrol) { String val1 = controller.controllerInput1.text; String val2 = controller.controllerInput2.text; print("$val1 $val2"); await controller.addNote(); } }, icon: Icon( Icons.forward, color: Colors.blueGrey, size: 36.0, ), ); }
补充说明
- obs是GetX提供的响应式变量包装器,你定义的
var items = <Word>[].obs本质是一个RxList,只有对这个RxList做增删改操作(比如add、remove、assignAll)才会触发更新通知 - Obx是响应式Widget,只要它包裹的Widget中用到了任意obs变量,变量更新时Obx会自动重绘内部的Widget,不需要手动调用setState、update或者刷新页面
内容的提问来源于stack exchange,提问作者Salih Balsever
相关产品推荐
相关产品推荐

