左右鞋垫传感器数据Firebase同步异常问题求助
智能鞋垫Firebase数据同步异常解决方案
问题背景
我有左右两只智能鞋垫,需将两者生成的数据每1秒发送至Firebase平台。目前使用left_timer.scheduleAtFixedRate和right_timer.scheduleAtFixedRate两个定时器实现每秒发送逻辑,但数据存在同步异常:实际行走时仅单脚接触鞋垫,数据却显示双脚同时着地,怀疑该问题由数据发送流程延迟导致,求可行解决方案。
问题根源分析
- 两个独立定时器无法保证严格同步,左右数据的发送时间点存在偏差,导致不同时刻的数据被标记为同一秒
- 数据缓存字典
leftDataDict/rightDataDict持续累积数据,直到发送时才清空,可能包含多帧不同时刻的传感器数据 - Firebase异步发送的回调中才清空数据,若发送延迟,后续接收的新数据会覆盖旧数据,导致数据混乱
- 蓝牙接收数据时,每条消息都生成独立时间戳,同一秒内的多条数据时间标记不一致,无法准确对应同一时刻的状态
解决方案
1. 统一定时器,同步发送左右数据
放弃两个独立定时器,改用单个全局定时器同时处理左右鞋垫的数据发送,确保同一时间点提交数据到Firebase。
// 全局变量 private Timer syncTimer; private boolean isLeftRunning = false; private boolean isRightRunning = false; private SimpleDateFormat secondFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); // 修改startLeftBtn点击事件 startLeftBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (is_L_insole_connected) { if (is_L_insole_started) { left_insole_device_interface.stopInsole(); is_L_insole_started = false; startLeftBtn.setText("Start Left"); isLeftRunning = false; checkAndStopSyncTimer(); } else { left_insole_device_interface.startInsole(); is_L_insole_started = true; startLeftBtn.setText("Stop Left"); isLeftRunning = true; checkAndStartSyncTimer(); } } else { Toast.makeText(Visualization.this, "Left Insole Not Connected!", Toast.LENGTH_SHORT).show(); } } }); // 修改startRightBtn点击事件 startRightBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (is_R_insole_connected) { if (is_R_insole_started) { right_insole_device_interface.stopInsole(); is_R_insole_started = false; startRightBtn.setText("Start Right"); isRightRunning = false; checkAndStopSyncTimer(); } else { right_insole_device_interface.startInsole(); is_R_insole_started = true; startRightBtn.setText("Stop Right"); isRightRunning = true; checkAndStartSyncTimer(); } } else { Toast.makeText(Visualization.this, "Right Insole Not Connected!", Toast.LENGTH_SHORT).show(); } } }); // 定时器控制方法 private void checkAndStartSyncTimer() { if (syncTimer == null && (isLeftRunning || isRightRunning)) { syncTimer = new Timer(); syncTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { runOnUiThread(() -> { if (isLeftRunning) { sendCurrentInsoleData(leftDataDict, "Left_Insole"); } if (isRightRunning) { sendCurrentInsoleData(rightDataDict, "Right_Insole"); } }); } }, 1000, 1000); } } private void checkAndStopSyncTimer() { if (syncTimer != null && !isLeftRunning && !isRightRunning) { syncTimer.cancel(); syncTimer = null; } }
2. 按整秒窗口缓存数据,避免累积
修改蓝牙接收逻辑,用整秒时间戳作为键,每个时间窗口只存储当前秒的最新数据,而非持续添加:
// 左鞋垫onMessageReceived中替换时间戳逻辑 if(is_L_insole_started){ // ... 原有数据解析逻辑 ... String currentSecond = secondFormatter.format(new Date()); // 直接覆盖当前秒的数据,确保每秒仅保留最新状态 leftDataDict.put(currentSecond, Arrays.toString(l_data_double_arr)); // ... 原有数据重置逻辑 ... } // 右鞋垫onMessageReceived同理修改 if(is_R_insole_started){ // ... 原有数据解析逻辑 ... String currentSecond = secondFormatter.format(new Date()); rightDataDict.put(currentSecond, Arrays.toString(r_data_double_arr)); // ... 原有数据重置逻辑 ... }
3. 优化Firebase发送逻辑,避免数据冲突
修改发送方法,先复制当前数据再清空缓存,避免异步发送时数据被覆盖:
public void sendCurrentInsoleData(Map<String, Object> data, String of_insole) { if (data.isEmpty()) return; // 复制当前数据,避免清空操作影响正在发送的内容 Map<String, Object> dataCopy = new HashMap<>(data); data.clear(); // 立即清空缓存,准备接收下一秒数据 db.collection("Experiments").document(PATIENT_NAME).set(patientRecord); db.collection("Experiments") .document(PATIENT_NAME) .collection(of_insole) .document(secondFormatter.format(new Date())) .set(dataCopy) .addOnSuccessListener(unused -> { Toast.makeText(Visualization.this, of_insole + "数据已保存", Toast.LENGTH_SHORT).show(); }) .addOnFailureListener(e -> { Toast.makeText(Visualization.this, of_insole + "数据保存失败", Toast.LENGTH_SHORT).show(); // 保存失败时将数据放回缓存,避免丢失 data.putAll(dataCopy); }); }
4. 线程安全处理数据缓存
蓝牙接收在后台线程,定时器发送在UI线程,改用ConcurrentHashMap保证线程安全:
// 替换原有HashMap定义 private Map<String, Object> leftDataDict = new ConcurrentHashMap<>(); private Map<String, Object> rightDataDict = new ConcurrentHashMap<>();
内容的提问来源于stack exchange,提问作者lead step
相关产品推荐
相关产品推荐

