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

React Native中Expo-av库页面跳转时无法卸载音频问题求助

解决Expo AV背景音页面跳转后持续播放的问题

你的问题核心在于页面跳转时原组件并未卸载(比如React Navigation栈导航中,旧页面只是被压入栈底,并未销毁),导致原本的useEffect清理函数无法触发。下面是具体的修复方案:

修复步骤

1. 导入导航焦点监听钩子

确保已安装并配置React Navigation,然后导入useFocusEffect:

import { useFocusEffect } from '@react-navigation/native';

2. 替换原useEffect为焦点监听

用useFocusEffect替代普通useEffect,它会在页面获得焦点时执行播放逻辑,失去焦点(跳转至其他页面)时自动执行清理操作:

useFocusEffect(
  React.useCallback(() => {
    let soundInstance;

    // 页面获得焦点时播放背景音
    async function playBackgroundSound() {
      const { sound } = await Audio.Sound.createAsync(
        require('../assets/audio/BackgroundMusic.mp3')
      );
      soundInstance = sound;
      await sound.playAsync();
    }

    playBackgroundSound();

    // 页面失去焦点时停止并卸载声音
    return async () => {
      if (soundInstance) {
        await soundInstance.stopAsync();
        await soundInstance.unloadAsync();
      }
    };
  }, [])
);

3. 调整手动播放逻辑(可选)

如果需要保留手动播放按钮,可将播放逻辑抽离,同时确保焦点变化时仍能正确管理声音实例:

const BookSelection = () => {
  LogBox.ignoreLogs(['new NativeEventEmitter']);
  let soundInstance = null;

  async function playSound() {
    if (soundInstance) {
      await soundInstance.unloadAsync();
    }
    const { sound } = await Audio.Sound.createAsync(
      require('../assets/audio/BackgroundMusic.mp3')
    );
    soundInstance = sound;
    await sound.playAsync();
  }

  useFocusEffect(
    React.useCallback(() => {
      return async () => {
        if (soundInstance) {
          await soundInstance.stopAsync();
          await soundInstance.unloadAsync();
          soundInstance = null;
        }
      };
    }, [])
  );

  // ... 其余代码不变
};

完整修改后的代码示例

import React from 'react';
import { View, ImageBackground, FlatList, Button, StyleSheet } from 'react-native';
import { Audio } from 'expo-av';
import Constants from 'expo-constants';
import { useFocusEffect } from '@react-navigation/native';

const BookSelection = () => {
  LogBox.ignoreLogs(['new NativeEventEmitter']);

  useFocusEffect(
    React.useCallback(() => {
      let soundInstance;

      async function playBackgroundSound() {
        console.log('Loading Sound');
        const { sound } = await Audio.Sound.createAsync(
          require('../assets/audio/BackgroundMusic.mp3')
        );
        soundInstance = sound;
        console.log('Playing Sound');
        await sound.playAsync();
      }

      playBackgroundSound();

      return async () => {
        if (soundInstance) {
          console.log('Stopping and Unloading Sound');
          await soundInstance.stopAsync();
          await soundInstance.unloadAsync();
        }
      };
    }, [])
  );

  return (
    <ImageBackground
      source={require('../assets/images/book1/page1.png')}
      style={styles.backgroundImage}
    >
      <View style={styles.container}>
        {/* 如需手动播放可保留按钮,否则移除 */}
        {/* <Button title="Play Sound" onPress={playSound} /> */}
        <FlatList
          data={booksData}
          renderItem={({ item }) => <Book book={item} />}
          showsVerticalScrollIndicator={false}
        />
      </View>
    </ImageBackground>
  );
};

const styles = StyleSheet.create({
  backgroundImage: {
    flex: 1,
    resizeMode: 'cover',
  },
  container: {
    flex: 1,
    paddingHorizontal: '5%',
    top: Constants.statusBarHeight,
  },
});

export default BookSelection;

关键说明

  • useFocusEffect是React Navigation专为页面焦点变化设计的钩子,比普通useEffect更适配导航场景,能精准捕捉页面显示/隐藏状态。
  • 清理函数中先执行stopAsync()再执行unloadAsync(),确保声音完全停止后再释放资源,规避异步操作顺序问题。
  • 用useCallback包裹逻辑,避免组件重渲染时重复创建函数,提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:22:35