You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter的StreamBuilder中存储Firebase Cloud Messaging通知?

问题解决思路

一、循环未执行的原因及修复

你的循环for (var message in message.data)没触发,核心是两个问题:

  • message.data是Map<String, String>类型,直接遍历Map只会拿到key,且如果消息的data字段为空,循环自然不会执行。要遍历键值对,得用message.data.entries
  • 循环变量名message和外层的RemoteMessage message重名,会导致变量覆盖,存在编译隐患

修复后的循环示例:

// 遍历消息的data字段键值对
for (var entry in message.data.entries) {
  print('Key: ${entry.key}, Value: ${entry.value}');
  // 可将data内容添加到消息记录
  messagesShow.add('${entry.key}: ${entry.value}');
}

二、存储所有通知的修复方案

你只能单次获取一条消息,是因为FirebaseMessaging.onMessage流每次收到推送只会触发一次(传递单条消息),且原代码中notifications的状态维护不当,导致旧消息丢失。

1. 正确维护通知列表状态

把通知列表改为StatefulWidget的状态变量,确保消息不会因组件重建丢失:

class _NotificationPageState extends State<NotificationPage> {
  // 用状态变量存储所有通知
  final List<RemoteMessage> _notifications = [];
  late StreamSubscription<RemoteMessage> _messageSubscription;

  @override
  void initState() {
    super.initState();
    // 监听FCM前台消息,添加到通知列表
    _messageSubscription = FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      setState(() {
        _notifications.add(message);
      });
      _messageController.add('New Message');
    });
  }

  @override
  void dispose() {
    _messageSubscription.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('通知')),
      body: _notifications.isEmpty
          ? const Center(child: Text('暂无通知'))
          : ListView.builder(
              itemCount: _notifications.length,
              itemBuilder: (context, index) {
                final message = _notifications[index];
                return Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(message.notification?.title ?? '无标题'),
                      const SizedBox(height: 10),
                      Text(message.notification?.body ?? '无内容'),
                      // 可选:展示消息的data字段内容
                      if (message.data.isNotEmpty)
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const SizedBox(height: 10),
                            const Text('附加数据:', style: TextStyle(fontWeight: FontWeight.bold)),
                            ...message.data.entries.map((entry) => Text('${entry.key}: ${entry.value}')),
                          ],
                        ),
                    ],
                  ),
                );
              },
            ),
    );
  }
}

2. 为什么不用原StreamBuilder?

原StreamBuilder的snapshot每次只包含当前收到的单条消息,无法直接维护历史消息列表。改用StreamSubscription手动监听并更新状态变量,能更可靠地存储所有通知。

3. 持久化通知(可选)

如果需要APP重启后保留通知,可使用shared_preferences或本地数据库(如Hive、sqflite)将通知列表序列化存储,初始化时再读取恢复。

内容的提问来源于stack exchange,提问作者Anurag Prasad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:43:26