Proper way to unload sound with unloadAsync if it can be replayed.

  1. SDK Version: 42.0.5 , expo-av 9.2.3
  2. Platforms: iOS and Android
  3. expo-av , Audio

I have a component where different short sounds can be played multiple times.
What is the proper way to use unloadAsync to clear sound from the memory when I will not need them anymore (something like “before component will unmount”) ?

  • I tried to call createAsync every time I click on a button and unloadAsync after sound did finished. But there is a huge delay (~300-600ms) before play especially on Android even for short sounds. With such a long delay click sound doesn’t feel like a callback to touch.

  • I tried to call unloadAsync in a component destroy callback but sound objects are already undefined at this point.

There is my simplified component:

let soundSounds = {
    "de": require("./../../sounds/sound_m_de.mp3"),
    "en_us": require("./../../sounds/sound_m_en_us.mp3"),
    "fr": require("./../../sounds/sound_m_fr.mp3"),

let letterSounds = {
    "de": require("./../../sounds/letter_m_de.mp3"),
    "en_us": require("./../../sounds/letter_m_en_us.mp3"),
    "fr": require("./../../sounds/letter_m_fr.mp3"),

function PronounceSettings({route, start, utils, navigation}){

        const [clickSound, setClickSound] = useState();
        const [letterSound, setLetterSound] = useState();
        const [soundSound, setSoundSound] = useState();

        useEffect(() => {
            return () => {
                // that doesn't work. clickSound and others are already undefined

       const _initSounds = async() => {
                await Audio.setAudioModeAsync({
                    playsInSilentModeIOS: true,
                const {sound} = await Audio.Sound.createAsync(require('./../../sounds/click.mp3'));

                const {sound: letterSound} = await Audio.Sound.createAsync(letterSounds[utils.locale]);

                const {sound: soundSound} = await Audio.Sound.createAsync(soundSounds[utils.locale]);

                return true

        const _playSound = async(sound) => {
             if (sound){
                  await sound.setPositionAsync(0);

        return <View>
               <TouchableOpacity onPress={()=>{_playSound(clickSound)}}>
                   <Text>go back button</Text>

               <Text>Choose pronounciation</Text>
               <TouchableOpacity onPress={()=>{_playSound(letterSound)}}>
               <TouchableOpacity onPress={()=>{_playSound(soundSound)}}>

               <TouchableOpacity onPress={()=>{_playSound(clickSound)}}>
                   <Text>save button</Text>


Looks like formulating a problem helps to solve it.
Answer to my own question. Just use useEffect callback for every sound:

        return clickSound ? () => {
          clickSound.unloadAsync(); }
          : undefined;

        return letterSound ? () => {
          letterSound.unloadAsync(); }
      : undefined;

        return soundSound ? () => {
          soundSound.unloadAsync(); }
      : undefined;

1 Like

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.