Home > OS >  Kotlin for loop does not wait for function to finish
Kotlin for loop does not wait for function to finish

Time:09-10

I have the following for loop.

for (song in songArray){
    playSong(song)
}

and playSong as below:

fun playSong(song){
mediaPlayer.create(context, R.raw.song)
mediaPlayer.start

mediaPlayer?.setOnCompletionListener {
        mediaPlayer!!.release()
        mediaPlayer = null
        }
}

The for loop does not wait for the entire playSong function to complete, and just immediately starts the next song. I want the the listener to be heard and the song to complete before iterating to the next song. If you could give me some guidance on this, I would appreciate it.

CodePudding user response:

Instead of using for loop play songs from array when the previous one finishes

fun playSongArray(songArray: IntArray) {
    var i = 0
    mediaPlayer.create(context, R.raw.songArray[0])
    mediaPlayer.start
    mediaPlayer?.setOnCompletionListener {
        if (i < songArray.size) {
            mediaPlayer.create(context, R.raw.songArray[1])
            mediaPlayer.start
            i  
        } else {
            mediaPlayer!!.release()
            mediaPlayer = null
        }
    }
}

CodePudding user response:

Play the next song when the current one completed..

var currentSongIndex = 0;
var nextSong = songArray.elementAt(currentSongIndex)
mediaPlayer.create(context, nextSong)
mediaPlayer.start()

mediaPlayer?.setOnCompletionListener {
        currentSongIndex  
        if (currentSongIndex >= songArray.length){
           mediaPlayer!!.release()
           mediaPlayer = null
           return
        }
        var nextSong = songArray.elementAt(playlistPos)
        mediaPlayer.create(context, nextSong)
        mediaPlayer.start()
    }
}

CodePudding user response:

Here's how it could be done with coroutines. First, you need to create a suspend function version of playing media and waiting for it to finish. Since a completion listener is not a one-shot callback, I think it is more appropriate to use callbackFlow instead of suspendCoroutine.

suspend fun MediaPlayer.startAndAwait() { 
    callbackFlow { 
        setOnCompletionListener {
            trySendBlocking(Unit)
        }
        awaitClose { setOnCompletionListener(null) }
    }.first()
    start()
}

Then you can use this function in a coroutine, so you can loop sequentially:

suspend fun playSong(song: Int){
    MediaPlayer.create(context, song).apply {
        mediaPlayer = this // so you can cancel playback from elsewhere
        startAndAwait()
        release()
        mediaPlayer = null
    }
}

//In a coroutine:

for (song in songArray){
    playSong(song)
}
  • Related