Flutter:如何等待ChangeNotifier构造初始化完成后渲染ListView
问题核心原因
原来的代码存在两个会直接导致功能失效的逻辑漏洞:
- 初始空值无防护:
altitudes声明时没有设置初始值,构造函数内触发的_initialise是异步执行的任务,页面首次渲染时该值仍为null,直接访问.length属性会触发空指针异常 - 状态变更无通知:
_initialise拿到异步加载的列表完成赋值后,没有调用状态通知方法,就算数据加载完成,绑定了该状态的UI也不会触发重建重新渲染 - 额外注意:Dart中的构造函数是同步执行的,不会等待内部触发的异步任务完成再返回,不存在“等列表加载完再走渲染逻辑”的默认等待机制
分步修复方案
1. 改造Notifier状态逻辑
需要从三个维度调整Notifier的实现:
- 给
altitudes设置初始空列表,从根源避免空指针 - 新增加载状态标记,用来区分不同渲染阶段
- 数据更新、状态切换时主动调用
notifyListeners()通知绑定的UI层重建
调整后的Notifier代码:
class TablesNotifier with ChangeNotifier { final jsonSelectorService = locator<JsonSelectorService>(); // 初始化为空列表,避免首次渲染空指针 List<AltitudeModel> altitudes = []; // 新增加载状态标记 bool isLoading = false; TablesNotifier(){ _initialise(); } Future _initialise() async{ // 标记为加载中,通知UI展示加载态 isLoading = true; notifyListeners(); // 执行异步列表加载 altitudes = await jsonSelectorService.altitudes(); // 加载完成,切换状态并通知UI更新列表 isLoading = false; notifyListeners(); } }
2. 改造页面渲染分支
不要在页面首次build时直接渲染列表,要根据当前Notifier的状态做分支判断,匹配对应阶段的UI:
- 加载状态时展示居中的加载指示器,避免白屏或者崩溃
- 空列表时展示友好的空态提示
- 列表有数据时再正常渲染
ListView.builder
调整后的页面构建逻辑:
Widget _buildBody(BuildContext context) { final tableProvider = Provider.of<TablesNotifier>(context); // 加载中分支 if (tableProvider.isLoading) { return const Center(child: CircularProgressIndicator()); } // 空列表分支 if (tableProvider.altitudes.isEmpty) { return const Center(child: Text('暂无海拔数据')); } // 正常列表渲染分支 return ListView.builder( itemCount: tableProvider.altitudes.length, itemBuilder: (context, index) { final altitudeItem = tableProvider.altitudes[index]; return ListTile( title: Text('$altitudeItem'), ); }, ); }
补充说明:如果后续需要处理加载失败的场景,只需要在Notifier中新增错误信息的状态标记,在页面渲染时增加错误态的分支处理即可,整体逻辑框架和上述实现保持一致。
内容的提问来源于stack exchange,提问作者user6551314
相关产品推荐
相关产品推荐

