react-native - 在我卸载 Audio.Sound() 并移动屏幕后调用方法

标签 react-native expo react-native-ios expo-av

我正在扩展 timer component 的功能为计时器的最后 3 秒添加蜂鸣声。这很好用,问题归根结底是说完了。我正在执行以下操作:

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

在最后一次蜂鸣声播放后大约一秒钟,我导航到以下屏幕,我收到一个错误,我将在下面完整地跳过该错误。 expo-av 库似乎在我的声音对象上调用了一个查找操作,但我的组件不再存在:

[未处理的 promise 拒绝:错误:寻求中断。]

我尝试了以下方法但没有成功:

  • 调用 loadAsyncunloadAsync wait 调用
  • 尝试将 setOnPlaybakStatusUpdate 设置为 null 以尝试阻止 statusUpdate 调用
  • 我什至尝试过不通过 unloadAsync 卸载声音

我的代码是:

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

最佳答案

我想我已经解决了。问题不在于声音 API 或 expo-av。问题似乎是有问题的计时器组件如何处理回调。我怀疑,由于下一个屏幕也有一个组件,因此该组件以某种方式将新的回调触发到旧组件中。我已向组件的每个实例添加了唯一的 ID,并且不再出现错误:

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

注意:因此,我相信这个问题和答案仅在您使用 https://github.com/talalmajali/react-native-countdown-component 时才相关。 .

感谢您的阅读。

关于react-native - 在我卸载 Audio.Sound() 并移动屏幕后调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63490637/

相关文章:

android - React-Native 在推送通知上呈现页面

react-native - 博览会-本地通知在设备上不起作用

ios - 在 iOS 上自动填充后 react-native Keyboard.dismiss() 不工作

react-native - React Native use_native_modules 文档

ios - React Native 显示神秘的堆栈跟踪而不是文件名

ios - 为什么在部署Expo项目时无法在测试飞行中看到内部测试选项

javascript - 如何从 child 调用父函数 - react-native

android - 将 ReactNative 用于 UI,但仍将 native API 用于其他用途

ios - React-Native ScrollView 在 setState 上丢失了位置

ios - 必须将 AirGoogleMaps 目录添加到您的 xCode 项目以支持 iOS React Native 上的 GoogleMaps