在我卸载并移动屏幕后在Audio.Sound上调用方法

问题描述

我正在扩展timer component功能,以在计时器的最后3秒内添加beep声音。效果很好,毕竟问题已经解决了。我正在执行以下操作:

  1. 将计时器组件包装到新的功能组件上
  2. 初始化组件正文中的Audio.sound()
  3. 使用useEffect初始加载声音
  4. 在每个计时器事件中,我检查是否应该播放声音并使用replayAsync
  5. 播放声音
  6. useEffect清理中,我用unloadAsync卸载声音对象

在发出最后一个提示音后大约一秒钟,并且我已导航至以下屏幕,我收到一条错误消息,我将完整地从下面进行检查。似乎expo-av库正在对声音对象调用搜索操作,但是我的组件不再存在:

[Unhandled promise rejection: Error: Seeking interrupted.]

我尝试以下操作均未成功:

  • 拨打loadAsyncunloadAsync的电话以等待呼叫
  • 尝试setonPlaybakStatusUpdate为空以尝试阻止statusUpdate调用
  • 我什至试图不通过unloadAsync卸载soudn

我的代码是:

import React from 'react'
import CountDown from 'react-native-countdown-component'
import { Audio } from 'expo-av'
const BEEP_START = 3

const CountDownBeep = (props) => {
  console.log('Sound Created')
  const beepSound = new Audio.sound()

  React.useEffect(() => {
      async function loadSound() {
          console.log("Sound Initialized")
          await beepSound.loadAsync(require('../assets/sounds/beep.wav'),{
              shouldplay: false,isLooping: false,})
          // This is not by design,just one of my attempts to get rid of the error
          beepSound.setonPlaybackStatusUpdate()
      }

      loadSound()

      // Cleanup,tried with async and without
      return async () => {
          console.log('Sound destroyed')
          await beepSound.unloadAsync()
      }
  })

  const countDownTimerChangedHandler = (timeLeft) => {

      // This works fine
      if (timeLeft <= BEEP_START + 1 && timeLeft > 0) {
          console.log('Sound Played:',timeLeft)
          beepSound.replayAsync()
      }
  }

  return (
      <CountDown
          {...props}
          onChange={(timeLeft) => countDownTimerChangedHandler(timeLeft)}
      />
  )
}

export default CountDownBeep

功能为100%,但是在导航至下一个屏幕几秒钟或一两秒钟后,出现以下错误

[Unhandled promise rejection: Error: Seeking interrupted.]
- node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:103:50 in promiseMethodWrapper
- node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js:15:23 in moduleName.methodInfo.name
- node_modules/expo-av/build/Audio/Sound.js:138:24 in replayAsync
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:293:29 in invoke
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:154:27 in invoke
- node_modules/regenerator-runtime/runtime.js:189:16 in PromiseImpl$argument_0
- node_modules/promise/setimmediate/core.js:45:6 in tryCallTwo
- node_modules/promise/setimmediate/core.js:200:22 in doResolve
- node_modules/promise/setimmediate/core.js:66:11 in Promise
- node_modules/regenerator-runtime/runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules/regenerator-runtime/runtime.js:211:38 in enqueue
- node_modules/regenerator-runtime/runtime.js:238:8 in exports.async
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:293:29 in invoke
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:154:27 in invoke
- node_modules/regenerator-runtime/runtime.js:189:16 in PromiseImpl$argument_0
- node_modules/promise/setimmediate/core.js:45:6 in tryCallTwo
- node_modules/promise/setimmediate/core.js:200:22 in doResolve
- node_modules/promise/setimmediate/core.js:66:11 in Promise
- node_modules/regenerator-runtime/runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules/regenerator-runtime/runtime.js:211:38 in enqueue
- node_modules/regenerator-runtime/runtime.js:238:8 in exports.async
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
* components/CountDownBeep.js:31:24 in countDownTimerChangedHandler
* components/CountDownBeep.js:39:22 in CountDown.props.onChange
- node_modules/react-native-countdown-component/index.js:115:21 in CountDown#updateTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:135:14 in _callTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:387:16 in callTimers
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:425:19 in __callFunction
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:112:6 in __guard$argument_0
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:373:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:111:4 in callFunctionReturnFlushedQueue
* [native code]:null in callFunctionReturnFlushedQueue

解决方法

我想我已经解决了。问题不在于Sound API或expo-av。问题似乎是有问题的计时器组件如何处理回调。我怀疑,由于下一个屏幕还包含一个组件,因此该组件将新的回调触发到旧的组件中。我为组件的每个实例添加了唯一的ID,并且停止出现错误:

 <CountDown
            {...props}
            id={new Date().toTimeString()}
            onChange={(timeLeft) => countDownTimerChangedHandler(timeLeft)}
        />

注意:因此,我相信只有在使用https://github.com/talalmajali/react-native-countdown-component时此问题和答案才有意义。

感谢您阅读。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...