调用NotifyListeners后Consumer Widget未重建的Flutter聊天应用问题
问题:聊天列表数据更新后Widget未重建
我正在开发一款聊天应用,调用更新聊天列表的方法后,数据处理一切正常,但对应的Widget却未重建。试过context.read()、context.watch()、Provider.of(context, listen: true)、ChangeNotifierProxyProvider都没用,只有重启应用才能让UI重建,求解决办法。
相关代码
主入口代码
void main() { runApp(MultiProvider(providers: [ ChangeNotifierProvider(create: (context) => UsersProvider()), ChangeNotifierProvider(create: (context) => ChatProvider()), ], child: const MyApp())); }
UsersProvider代码
class UsersProvider extends ChangeNotifier { UsersProvider(){ getChats(); } List<Chats> get chats=> _chats; List<Chats> _chats = []; Future getChats() async { final json = await UsersRepo().getChatLists(); if (json == null) { return; } if (json['status']) { ChatListModel _model = ChatListModel.fromJson(json); _chats = _model.chats ?? []; notifyListeners(); } } }
界面代码(ChatList)
class ChatList extends StatelessWidget { const ChatList({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.appBg, appBar: AppBar( title: Text('Users'), backgroundColor: AppColors.appBgLight, ), body: chatListWidget(context), ); } Widget chatListWidget(BuildContext context) { return Consumer<UsersProvider>( builder: (BuildContext context, provider, Widget? child) { return ListView.separated( padding: EdgeInsets.symmetric(vertical: 20), itemCount: provider.chats.length, separatorBuilder: (c, i) => sbh(15), itemBuilder: (c, i) { Chats chat = provider.chats[i]; return ListTile( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (c) { return ChatScreen( user: Users( name: chat.receiver?.name, sId: chat.receiver?.id), ); }, ), ); context.read<ChatProvider>().connectToUser(chat.receiver?.id); }, leading: userImageWidget((chat.receiver?.name ?? "")[0].toUpperCase()), subtitle: Text( chat.lastMessage ?? "", style: TextStyle( color: Colors.white70, fontSize: 12, ), ), trailing: CircleAvatar( radius: 15, backgroundColor: Colors.green, child: Center( child: Text( '${chat.unReadMessageCount}', style: TextStyle(fontSize: 12, color: Colors.white), )), ), title: nameWidget(chat.receiver?.name ?? ''), ); }, ); }, ); } }
Chats模型类代码
class Chats { String? lastMessage; String? messageTime; int? unReadMessageCount; Chats( {this.lastMessage, this.messageTime, this.unReadMessageCount}); Chats.fromJson(Map<String, dynamic> json) { lastMessage = json['lastMessage']; messageTime = json['messageTime']; unReadMessageCount = json['unReadMessageCount']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['lastMessage'] = this.lastMessage; data['messageTime'] = this.messageTime; data['unReadMessageCount'] = this.unReadMessageCount; return data; } }
解决方向
1. 确保notifyListeners()在主线程调用
异步操作完成后可能处于子线程,需切换到主线程通知UI更新:
Future getChats() async { final json = await UsersRepo().getChatLists(); if (json == null) { return; } if (json['status']) { ChatListModel _model = ChatListModel.fromJson(json); _chats = _model.chats ?? []; // 切换到主线程执行通知 WidgetsBinding.instance.addPostFrameCallback((_) { notifyListeners(); }); } }
2. 排查Provider实例重复创建问题
检查ChatList或其父Widget是否重复嵌套了ChangeNotifierProvider<UsersProvider>,导致界面监听的Provider和更新数据的Provider不是同一个实例。
3. 验证数据解析正确性
在notifyListeners()前添加打印,确认_chats确实更新为最新数据:
print("更新后聊天列表长度:${_chats.length}");
4. 用Selector替代Consumer缩小监听范围
Selector可只监听chats字段的变化,避免不必要的重建,同时确保监听数据源正确:
Widget chatListWidget(BuildContext context) { return Selector<UsersProvider, List<Chats>>( selector: (context, provider) => provider.chats, builder: (context, chats, child) { return ListView.separated( padding: EdgeInsets.symmetric(vertical: 20), itemCount: chats.length, separatorBuilder: (c, i) => sbh(15), itemBuilder: (c, i) { Chats chat = chats[i]; // 剩余代码不变 }, ); }, ); }
5. 尝试改为StatefulWidget
若ChatList被缓存(如PageView的keepAlive机制),StatelessWidget可能无法触发重建,改为StatefulWidget并手动监听依赖变化:
class ChatList extends StatefulWidget { const ChatList({Key? key}) : super(key: key); @override State<ChatList> createState() => _ChatListState(); } class _ChatListState extends State<ChatList> { late UsersProvider _provider; @override void didChangeDependencies() { super.didChangeDependencies(); _provider = Provider.of<UsersProvider>(context); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.appBg, appBar: AppBar( title: const Text('Users'), backgroundColor: AppColors.appBgLight, ), body: ListView.separated( padding: const EdgeInsets.symmetric(vertical: 20), itemCount: _provider.chats.length, separatorBuilder: (c, i) => sbh(15), itemBuilder: (c, i) { Chats chat = _provider.chats[i]; // 剩余代码不变 }, ), ); } }
内容的提问来源于stack exchange,提问作者Muhammed Jasir
相关产品推荐
相关产品推荐

