这是我第一次与expo 合作,我学到了很多东西,但这仍然是我无法解决的问题.

我正在使用expo-av,对于简短的声音,我没有任何问题.他们踢球,然后我拨打unloadAsync(),那里没有问题.但说到背景音乐,我会停下来,卸载,确保useEffect正在恢复,但由于某种原因,即使在游戏结束后,我被送到游戏结束或胜利屏幕后,音乐仍在继续播放,如果出于某种原因,我试图开始另一场游戏,它将是一个音频叠加在另一个之上.

在负责设置回放的类内部:

 class AudioController {

    constructor() {

        this.bgMusic = new Audio.Sound()
        this.flipSound = new Audio.Sound()
        this.matchSound = new Audio.Sound()
        this.victorySound = new Audio.Sound()
        this.gameOverSound = new Audio.Sound()
    }

    
    loadAndPlay = async (audioObject, audioFile, loop = false, volume = 1.0) => {

        try {
            await audioObject.loadAsync(audioFile);
            audioObject.setIsLoopingAsync(loop);
            audioObject.setVolumeAsync(volume);
            await audioObject
                .playAsync()
                .then(async playbackStatus => {

                    if (!loop) {
                        setTimeout(() => {
                            audioObject.unloadAsync()
                        }, playbackStatus.playableDurationMillis)
                    }
                })
                .catch(error => {
                    console.log(error)
                })

        } catch (error) {
            console.log(error);
        }
    }


    playBgMusic = async () => {
        await this.loadAndPlay(this.bgMusic, bgMusic, true, 0.5); // Loop and set the volume to 50%
    }


    stopBgMusic = async () => {
        try {

            await this.bgMusic.stopAsync();
            await this.bgMusic.unloadAsync();

        } catch (error) {
            console.log(error);
        }
    }

    playFlipSound = async () => {
        await this.loadAndPlay(this.flipSound, flipSound);
    }

    playMatchSound = async () => {
        await this.loadAndPlay(this.matchSound, matchSound);
    }

    playVictorySound = async () => {
        await this.loadAndPlay(this.victorySound, victorySound);
    }

    playGameOverSound = async () => {
        await this.loadAndPlay(this.gameOverSound, gameOverSound);
    }
}


export default AudioController``



Inside the component where I want to use it.

`useEffect(() => {

    audioController.playBgMusic()

    resetTurn()
    setTimer(level)
    shuffleCards()

    return () => {

       console.log(' Start game cleanup executed')

audioController.stopBgMusic()
}
}, []);`

当然,我正确地实例化了音频控制器(否则其他声音将不起作用),并且我正在触发游戏结束和胜利功能.所以问题要么是我试图停止音乐的方式,要么是组件没有卸载.我也试着在它把我送到一个不同的屏幕之前,停止处理游戏的功能中的音乐,但仍然是一样的.我也try 了使用Reaction上下文,结果是一样的,如果我try 开始一个新游戏,音乐不会停止,新的实例将会启动.

推荐答案

Reaction本机导航生命周期不像Reaction那样工作,您需要监听焦点和模糊事件来检测组件是否被隐藏或显示,如下所示:

  useEffect(() => {
    const subscribe = navigation.addListener('focus', () => {
      // Screen was focused
      // Do something
      console.log('play sound');

      controller.playBackgroundMusic();
    });

    const unsubscribe = navigation.addListener('blur', () => {
      // Screen was blurred
      // Do something
      console.log(' Start game cleanup executed');
      controller.stopBackgroundMusic();
    });

    return unsubscribe;
  }, []);

您可以在以下位置了解更多信息:

https://reactnavigation.org/docs/navigation-lifecycle/

这是一个如何使用原生react 播放和停止背景音乐的小演示:

SandBox :https://snack.expo.dev/EjVXFzojr

App.js

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

// or any files within the Snack
import GameScene from './components/GameScene';
import IntroScene from './components/IntroScene';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          name="Intro"
          component={IntroScene}
          options={{title: 'Intro'}}
        />
        <Stack.Screen name="Game" component={GameScene} options={{title: 'Game'}} />
      </Stack.Navigator>

    </NavigationContainer>
  );
}

./Controls/AudioController.js

import {Audio} from "expo-av"

class AudioController {
  constructor() {
    this.backgroundMusic = new Audio.Sound();
  }

  loadAndPlay = async (audioObject, audioFile, loop = false, volume = 1.0) => {
    try {
      await audioObject.loadAsync(audioFile);
      audioObject.setIsLoopingAsync(loop);
      audioObject.setVolumeAsync(volume);
      await audioObject
        .playAsync()
        .then(async (playbackStatus) => {
          if (!loop) {
            setTimeout(() => {
              audioObject.unloadAsync();
            }, playbackStatus.playableDurationMillis);
          }
        })
        .catch((error) => {
          console.log(error);
        });
    } catch (error) {
      console.log(error);
    }
  };

  playBackgroundMusic = async () => {

    await this.loadAndPlay(
      this.backgroundMusic,
      require('../assets/FitGirl-Repacks.mp3'),
      true,
      1
    ); // Loop and set the volume to 50%
  };

  stopBackgroundMusic = async () => {
    try {
      await this.backgroundMusic.stopAsync();
      await this.backgroundMusic.unloadAsync();
    } catch (error) {
      console.log(error);
    }
  };
}
export function audioController(){
  return new AudioController()
}

./Components/IntroScene.js

import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Image, Button } from 'react-native';
import { audioController } from '../controllers/AudioController';

export default function IntroScene({ navigation }) {
  const startHandler = (event) => {
    navigation.navigate('Game');
  };

  const controller = audioController();

  useEffect(() => {
    const subscribe = navigation.addListener('focus', () => {
      // Screen was focused
      // Do something
      console.log('play sound');

      controller.playBackgroundMusic();
    });

    const unsubscribe = navigation.addListener('blur', () => {
      // Screen was focused
      // Do something
      console.log(' Start game cleanup executed');
      controller.stopBackgroundMusic();
    });

    return unsubscribe;
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>Intro Game</Text>
      <Button title="start" onPress={(event) => startHandler(event)} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    justifyContent: 'center',
    padding: 24,
  },
  paragraph: {
    margin: 24,
    marginTop: 0,
    fontSize: 14,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

./Components/GameScene.js

import { Text, View, StyleSheet, Image } from 'react-native';

export default function GameScene() {
  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>
        Play The Game
      </Text>
      <Image style={styles.logo} source={require('../assets/snack-icon.png')} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    justifyContent: 'center',
    padding: 24,
  },
  paragraph: {
    margin: 24,
    marginTop: 0,
    fontSize: 14,
    fontWeight: 'bold',
    textAlign: 'center',
  },
  logo: {
    height: 128,
    width: 128,
  }
});

React-native相关问答推荐

如何在Reaction Native DrawerNavigation中添加注销功能

try 使用JWT-DECODE解码令牌时出错

在 react native 平面列表中动态定位弹出窗口

有人可以帮我实现 Font.loadAsync

如何在react-native 的switch 内显示文本(是/否)

React Native - 动画宽度缩小

React-native -run-ios 错误无法构建 iOS 元素.我们运行了xcodebuild命令,但它以错误代码 65 退出

运行react应用程序时出错

你能在 Ubuntu 上构建 React Native 应用程序(Android 应用程序)吗?

NativeBase + Exponent Header

如何使用功能组件向 ref 公开功能?

react-native Http 拦截器

iOS 模拟器如何确认alert信息

DeviceInfo 原生模块未正确安装

如何在 React Native 中将图像放置在其他图像之上?

如何为 TouchableOpacity 组件创建禁用样式?

React Navigation 切换背景 colored颜色 和样式 StackNavigator

React Native 多行TextInput,文本居中

如何更改后退按钮标签,react-navigation

React Native:任务':app:transformDexArchiveWithExternalLibsDexMergerForDebug'的执行失败