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

React Native Expo应用音频无法重复播放问题求助

解决Expo Audio仅能播放一次的问题

问题核心:使用useAudioPlayer创建的播放器,首次播放完毕后会停留在音频结尾位置,再次调用play()不会触发从头播放,导致后续点击无法播放音效。

解决方法

每次播放音效前,先将音频位置重置到起始点,或者直接使用replayAsync()方法(该方法会自动重置位置并播放)。由于replayAsync()是异步方法,需要将处理函数改为异步函数。

修改后的代码

import { View, Text, StyleSheet } from "react-native";
import React, { useContext } from "react";
import Task from "./../Task/Task";
import { ModalContext } from "@/context/ModalContext";
import ModalText from "@/components/ModalText/ModalText";
import { PlayerInformationContext } from "@/context/PlayerInformation";
import { appText } from "@/assets/data";
import { useAudioPlayer } from "expo-audio";

const audioSource = require("./../../assets/sounds/game-bonus.mp3");

const Tasks = () => {
  const player = useAudioPlayer(audioSource);

  const {
    money,
    correctAnswersCount,
    seenAdsCount,
    language,
    canPlaySound,
    handleCorrectAnswers,
    handleSeenAdsCount,
    setMoney,
  } = useContext(PlayerInformationContext);

  const { toggleModal, setModalContent } = useContext(ModalContext);

  // 改为异步函数
  const handleTaskCompletion = async (
    taskCount,
    rewardAmount,
    resetCount,
    modalText
  ) => {
    if (taskCount === 10) {
      if (canPlaySound) {
        // 使用replayAsync重置并播放
        await player.replayAsync();
      }
      setMoney(money + rewardAmount);
      resetCount(0);
      setModalContent(<ModalText text={modalText} canShowButton={true} />);
      toggleModal();
    } else {
      setModalContent(
        <ModalText
          text={appText[language].rewardWarningMessage}
          canShowButton={true}
        />
      );
      toggleModal();
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.container_Text}>{appText[language].tasks}</Text>

      <Task
        title={appText[language].task1}
        credit="50"
        itemsLeft={correctAnswersCount}
        onPress={() =>
          handleTaskCompletion(
            correctAnswersCount,
            50,
            handleCorrectAnswers,
            appText[language].earned50Coin
          )
        }
      />

      <Task
        title={appText[language].task2}
        credit="75"
        itemsLeft={seenAdsCount}
        onPress={() =>
          handleTaskCompletion(
            seenAdsCount,
            75,
            handleSeenAdsCount,
            appText[language].earned75Coin
          )
        }
      />
    </View>
  );
};

export default Tasks;

const styles = StyleSheet.create({
  container: {
    width: "100%",
    height: "100%",
    alignItems: "center",
    justifyContent: "flex-start",
  },
  container_Text: {
    width: "100%",
    marginTop: 40,
    textAlign: "center",
    color: "white",
    fontWeight: "bold",
    fontSize: 32,
  },
});

另一种可选方案

如果不想使用异步函数,也可以手动重置播放位置后再播放:

if (canPlaySound) {
  player.setPositionAsync(0);
  player.play();
}

这种方式无需修改函数为异步,但setPositionAsync是异步操作,可能存在极少数情况下播放位置还没重置就开始播放的问题,推荐使用replayAsync的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 02:10:08