React Native iOS开启proximityMonitoringEnabled后setInterval停止运行求助
问题分析
当设备黑屏/锁屏后,移动端的JS线程会进入休眠状态,普通的setInterval会暂停执行,这就是你看不到定时器日志的原因。虽然InCallManager能维持通话活跃,但它默认不会阻止JS线程休眠。
解决方案
1. 基于时间戳计算通话时长(推荐)
放弃依赖定时器累加的方式,改用通话开始时间戳实时计算时长,这种方式不受锁屏影响,精度也更高。
代码示例:
import { useEffect, useRef, useState } from 'react'; // 定义你的CALL_STATE常量 const CALL_STATE = { CONNECTED: 'connected' }; function CallComponent({ callState, isVideo }) { const [callTime, setCallTime] = useState(0); const startTimeRef = useRef(null); const intervalRef = useRef(null); useEffect(() => { if (callState === CALL_STATE.CONNECTED && !isVideo) { // 记录通话开始的时间戳 startTimeRef.current = Date.now(); // 启动定时器实时计算时长 if (!intervalRef.current) { intervalRef.current = setInterval(() => { if (startTimeRef.current) { const elapsedSeconds = Math.floor((Date.now() - startTimeRef.current) / 1000); setCallTime(elapsedSeconds); } }, 1000); } } else { // 通话结束/切换状态时清理定时器和时间戳 if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; } startTimeRef.current = null; setCallTime(0); } // 组件卸载时清理资源 return () => { if (intervalRef.current) clearInterval(intervalRef.current); }; }, [callState, isVideo]); useEffect(() => { console.log('calltime', callTime); }, [callTime]); return <div>通话时长:{callTime}秒</div>; }
2. 使用后台定时器库(React Native 场景)
如果你的项目是React Native,可以用react-native-background-timer库实现后台运行的定时器,它能绕过系统锁屏后的JS线程休眠限制。
代码示例:
import BackgroundTimer from 'react-native-background-timer'; import { useEffect, useRef, useState } from 'react'; const CALL_STATE = { CONNECTED: 'connected' }; function CallComponent({ callState, isVideo }) { const [callTime, setCallTime] = useState(0); const intervalRef = useRef(null); useEffect(() => { if (callState === CALL_STATE.CONNECTED && !isVideo) { if (!intervalRef.current) { // 用后台定时器替代普通setInterval intervalRef.current = BackgroundTimer.setInterval(() => { setCallTime(prev => prev + 1); }, 1000); } } else { if (intervalRef.current) { BackgroundTimer.clearInterval(intervalRef.current); intervalRef.current = null; } setCallTime(0); } return () => { if (intervalRef.current) BackgroundTimer.clearInterval(intervalRef.current); }; }, [callState, isVideo]); useEffect(() => { console.log('calltime', callTime); }, [callTime]); return <div>通话时长:{callTime}秒</div>; }
注意:后台定时器会增加设备功耗,务必在通话结束后立即清理。
3. 监听InCallManager唤醒事件恢复计时
利用InCallManager的唤醒事件(比如屏幕点亮、传感器触发),在设备从黑屏状态恢复时,重新计算并恢复计时:
代码示例:
import { useEffect, useRef, useState } from 'react'; import InCallManager from 'react-native-incall-manager'; const CALL_STATE = { CONNECTED: 'connected' }; function CallComponent({ callState, isVideo }) { const [callTime, setCallTime] = useState(0); const startTimeRef = useRef(null); const intervalRef = useRef(null); useEffect(() => { if (callState === CALL_STATE.CONNECTED && !isVideo) { startTimeRef.current = Date.now(); startTimer(); } else { stopTimer(); startTimeRef.current = null; setCallTime(0); } // 监听设备唤醒事件 const handleWake = () => { if (callState === CALL_STATE.CONNECTED && !isVideo && startTimeRef.current) { // 唤醒时重新计算已流逝的时长 const elapsedSeconds = Math.floor((Date.now() - startTimeRef.current) / 1000); setCallTime(elapsedSeconds); // 如果定时器已停止,重启 if (!intervalRef.current) startTimer(); } }; InCallManager.addEventListener('wake', handleWake); return () => { InCallManager.removeEventListener('wake', handleWake); stopTimer(); }; }, [callState, isVideo]); const startTimer = () => { intervalRef.current = setInterval(() => { setCallTime(prev => prev + 1); }, 1000); }; const stopTimer = () => { if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; } }; useEffect(() => { console.log('calltime', callTime); }, [callTime]); return <div>通话时长:{callTime}秒</div>; }
内容的提问来源于stack exchange,提问作者famfamfam
相关产品推荐
相关产品推荐

