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

Expo开发中如何持续监听音频positionMillis展示剩余播放时长

实时获取音频播放进度的实现方案

问题根因

当前代码仅在音频首次加载、手动暂停、手动恢复三个操作节点主动拉取一次音频状态,在持续播放过程中没有触发状态获取逻辑,因此界面上的进度值不会随播放实时更新。

实现思路

  • 借助固定间隔轮询或官方自带的状态回调机制,在音频播放过程中持续拉取最新的播放状态,读取其中的positionMillis实时值
  • 当音频暂停、播放结束、组件销毁时,及时停止进度监听逻辑,避免无效的状态更新与内存泄漏
  • 剩余播放时长通过差值计算得到:Math.max(0, Math.ceil((durationMillis - positionMillis)/1000)),单位为秒

具体改造步骤

  1. 补充必要的状态与引用,用于存储实时进度和监听定时器
    const progressTimerRef = useRef(null);
    const [currentPlayProgress, setCurrentPlayProgress] = useState({
      positionMillis: 0,
      durationMillis: 0
    })
    
  2. 封装进度监听的启动、停止方法
    // 启动进度轮询
    const startProgressMonitor = (audioInstance) => {
      // 先清除已有定时器,避免重复触发
      stopProgressMonitor();
      // 每500ms拉取一次实时状态,平衡流畅度与性能消耗
      progressTimerRef.current = setInterval(async () => {
        if (!audioInstance) return;
        const latestStatus = await audioInstance.getStatusAsync();
        if (latestStatus.isLoaded) {
          setCurrentPlayProgress({
            positionMillis: latestStatus.positionMillis,
            durationMillis: latestStatus.durationMillis
          })
        }
      }, 500)
    }
    
    // 停止进度轮询
    const stopProgressMonitor = () => {
      if (progressTimerRef.current) {
        clearInterval(progressTimerRef.current);
        progressTimerRef.current = null;
      }
    }
    
  3. 在原有交互逻辑的对应节点挂载监听
    • 首次加载音频、开始自动播放时,调用startProgressMonitor(sound)启动进度监听
    • 触发音频暂停操作时,先调用stopProgressMonitor()停止监听,保留当前已获取的进度值
    • 触发音频恢复播放操作时,重新调用startProgressMonitor(sound)启动监听
  4. 补充组件卸载的清理逻辑,防止内存泄漏
    useEffect(() => {
      return () => {
        stopProgressMonitor();
        // 释放已加载的音频资源
        sound?.unloadAsync();
      }
    }, [sound])
    

更优实现:使用官方自带状态回调

如果使用的是Expo Audio新版本,无需手动编写定时器轮询,音频实例本身提供setOnPlaybackStatusUpdate方法,系统会在播放状态变化、进度推进时主动推送最新的播放状态,性能表现优于手动轮询,示例写法:

// 音频加载完成后直接绑定回调
sound.setOnPlaybackStatusUpdate((status) => {
  if (!status.isLoaded) return;
  // 同步实时进度到状态
  setCurrentPlayProgress({
    positionMillis: status.positionMillis,
    durationMillis: status.durationMillis
  })
  // 音频自然播放结束时,自动停止监听
  if (status.didJustFinish) {
    stopProgressMonitor();
  }
})

界面展示调整

直接基于实时进度值计算剩余秒数渲染到界面即可:

const remainSeconds = Math.max(0, Math.ceil(
  (currentPlayProgress.durationMillis - currentPlayProgress.positionMillis) / 1000
))
<Text>剩余播放时长:{remainSeconds} 秒</Text>

内容的提问来源于stack exchange,提问作者Tyler Joe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 16:15:03