Flutter Provider如何用数据库返回的Future对象列表触发组件重建
问题核心原因
你直接在Consumer的builder中调用异步方法getStudentList(),此时拿到的是Future对象而非实际的学生列表,无法直接遍历生成Widget;同时getStudentList()查询完数据后没有触发状态通知,就算数据加载完成UI也不会自动更新。
第一步:修改StudentProvider类
class StudentProvider extends ChangeNotifier { DataBaseHelper data = DataBaseHelper(); List<StudentModel>? student = []; List<StudentModel>? searchStudentList; // 标记是否正在加载,可用来做loading状态 bool isLoading = false; Future<List<StudentModel>> getStudentList() async { isLoading = true; notifyListeners(); // 通知UI加载状态变化 student = await data.getStudent(); isLoading = false; notifyListeners(); // 数据更新后通知UI重建 return student!; } void insert(StudentModel studentModel) async { print("reached insert in provider class"); await data.insertStudent(studentModel); // 插入完成后重新拉取列表,保证本地数据和数据库一致 await getStudentList(); } }
第二步:调整UI构建逻辑
你不需要在builder中主动调用getStudentList()获取数据,直接读取Provider中已经缓存的student列表构建UI即可,数据加载的触发时机可以放在页面初始化阶段:
// 把当前页面改为StatefulWidget,在initState中触发首次数据加载 @override void initState() { super.initState(); // 页面加载完成后首次拉取学生列表 WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of<StudentProvider>(context, listen: false).getStudentList(); }); } // 构建TabBarView部分的代码调整为: body: TabBarView(children: [ Consumer<StudentProvider>( builder: (context, StudentProvider provider, ch) { print("rebuild happened"); // 处理加载状态 if (provider.isLoading) { return const Center(child: CircularProgressIndicator()); } // 处理空列表状态 if (provider.student?.isEmpty ?? true) { return const Center(child: Text("暂无学生数据")); } return ListView( children: provider.student!.map((e) { return HomeScreen(student: e); }).toList(), ); }), // 其他Tab的组件... ])
如果不需要单独维护加载状态,也可以用FutureBuilder包裹直接处理异步逻辑:
body: TabBarView(children: [ Consumer<StudentProvider>( builder: (context, StudentProvider provider, ch) { return FutureBuilder<List<StudentModel>>( // 注意:要避免重复触发查询,可将future对象提前存在State变量中 future: provider.getStudentList(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text("加载失败:${snapshot.error}")); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text("暂无学生数据")); } return ListView( children: snapshot.data!.map((e) => HomeScreen(student: e)).toList(), ); }, ); }), ])
内容的提问来源于stack exchange,提问作者Vivek T V
相关产品推荐
相关产品推荐

