如何在Timer.periodic执行后添加延迟以避免数据丢失?
解决串行消息发送冲突问题
你的核心问题是多个发送请求并发/连续执行,导致接收端无法及时处理而丢数据。单纯给Timer加延迟无法从根本上解决问题(比如用户连续点击按钮时,延迟依然会导致冲突),最可靠的方案是给所有发送请求做串行队列处理,保证同一时间只有一个消息在发送,前一个发送完成后再处理下一个。
实现步骤
- 维护一个消息队列,存储待发送的消息;
- 用一个标记变量记录当前是否正在发送,避免并发执行;
- 统一通过入队方法触发发送,由队列处理器串行处理所有消息。
修改后的完整代码
import 'dart:collection'; import 'dart:async'; import 'package:flutter/material.dart'; class YourPage extends StatefulWidget { const YourPage({super.key}); @override State<YourPage> createState() => _YourPageState(); } class _YourPageState extends State<YourPage> { Timer? timer; // 消息队列:存储所有待发送的消息 final Queue<String> _messageQueue = Queue<String>(); // 标记当前是否正在发送消息 bool _isSending = false; @override void initState() { super.initState(); // Timer触发的Alive消息改为入队 timer = Timer.periodic(Duration(seconds: 5), (Timer t) => enqueueMessage('Alive')); } @override void dispose() { timer?.cancel(); super.dispose(); } // 将消息加入队列,并触发队列处理 void enqueueMessage(String message) { _messageQueue.add(message); _processMessageQueue(); } // 串行处理消息队列 Future<void> _processMessageQueue() async { // 如果正在发送或队列为空,直接返回 if (_isSending || _messageQueue.isEmpty) return; _isSending = true; try { // 取出队列头部的消息 final message = _messageQueue.removeFirst(); // 执行实际的发送逻辑(替换成你原来的_sendmessage实现) await _sendMessageToDevice(message); // 当前消息发送完成后,继续处理下一个 _processMessageQueue(); } finally { // 无论发送成功/失败,都标记发送状态结束 _isSending = false; } } // 实际的设备发送逻辑(原_sendmessage的核心代码) Future<void> _sendMessageToDevice(String message) async { // 这里替换成你的发送实现,比如蓝牙、网络通信 // 示例:等待发送完成(模拟耗时操作) await Future.delayed(Duration(milliseconds: 500)); print('已发送:$message'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('消息发送示例')), body: Center( child: ElevatedButton( // 按钮点击的消息也通过入队处理 onPressed: () => enqueueMessage('按钮触发的自定义数据'), child: Text('发送自定义数据'), ), ), ); } }
方案优势
- 彻底避免冲突:所有消息按顺序串行发送,接收端始终只处理一个消息;
- 适应性强:不管是Timer定时触发,还是用户高频点击按钮,都能保证消息不丢失;
- 容错性高:即使某个消息发送失败(比如网络中断),队列依然会处理后续消息(可根据需求添加重试逻辑)。
内容的提问来源于stack exchange,提问作者Marc Paul
相关产品推荐
相关产品推荐

