简体   繁体   中英

kotlin/android studio: wait for button to be pressed

so i am writing an app that asks the user to identify different notes that are being played to them. i imagine that to be done by playing one random note from a set of notes, then waiting for the user to press a button with the corresponding note, telling the user whether they put in the correct note, and, after a short delay, start the whole thing anew.

now my problem is the part with "waiting for the user to press the button".

Heres what i have done so far:

I have 12 buttons, one for each note of the chromatic scale, each with a corresponding onClickListener looking like this

        dobutton.setOnClickListener {
            var mediaPlayer: MediaPlayer? = MediaPlayer.create(this, R.raw.cping)
            mediaPlayer?.start()
            givenAnswer = 4 // etc. for all the other notes.

I then introduce some variables:

        var score = 0
        var index = 0
        var setAnswer = 0
        var givenAnswer = 0

I then have this while loop that ends after a number of rounds played and includes firstly this section that randomly selects one of the notes for playback and sets a correct answer, with corresponding files for playback and values for setAnswer for each note of the chromatic scale...

while (index != 11) {

    val randomGenerator = Random()
    val randomInt = randomGenerator.nextInt(11)

    when (randomInt) {
        0 ->{
            var mediaPlayer: MediaPlayer? = MediaPlayer.create(this, R.raw.abping)
            mediaPlayer?.start()
            println(pingsArray[0])
            setAnswer = 0
        }
        1 -> {
            var mediaPlayer: MediaPlayer? = MediaPlayer.create(this, R.raw.aping)
            mediaPlayer?.start()
            println(pingsArray[1])
            setAnswer = 1
        } // etc. for all the other notes...

...and then this block that compares the correct answer and the one given and increments the values accordingly.

run {
        if (setAnswer == givenAnswer) {
            index = index + 1
            score = score + 1
        }
        else {
            index = index + 1
        }
    }
}

After this, the while loop should begin anew. Then the whole thing presents the score.

Now my problem is that the whole while loop executes in one go, without giving the user any time to respond to anything. After spending a whole day googling and finding nothing useful, I finally decided to ask here. In case that it shows all too much: I just started coding a few days ago so please have mercy if my questions are a bit stupid and my code does not comply to the standards. It´s just a whole bunch of complicated stuff when you´re new to it...

Thank you!

If you simply intend to continuously wait until a user has clicked a button before playing the next sound, then honestly on each of your onClick listeners just add a new call to your function that generates the next media play (let's call it playNextSound() ) and immediately compare the result, for example:

dobutton.setOnClickListener {
    val mediaPlayer: MediaPlayer = MediaPlayer.create(this, R.raw.cping)
    mediaPlayer.start()

    index += 1
    if(setAnswer == thisButton){
        score += 1
    }

    if(index < 11){
        playNextSound()
    } else {
        showResults()
    }
}

Otherwise, if you intend to have some sort of a timeout, then that's a slightly different story. You may want to take advantage of a few asynchronous solutions to get around your conundrum: CountDownTimer or more advanced Handler & Runnable solution.

For the former, you can declare a timer that countdown to a specific time after the music is played, like so:

var timeoutCountdown: CountDownTimer = object: CountdownTimer(timeInMills, timeInMills) {

    override fun onFinish() {
        //Do something to inform the user he has run out of time. For example:
        showErrorDialog()
        index += 1
        if(index < 11){
            playNextSound()
        } else {
            showResults()
        }
    }

    override fun onTick(p0: Long) {
        //Ignore, unless you want to do something here.   
    }
}

and then in playNextSound() itself, after playing the sound, call timeoutCountdown.start() . Then, in each of the onClickListener s, do the same thing as the simpler implementation above and just add one line:

dobutton.setOnClickListener {
    //ADD THIS LINE TO STOP THE COUNTDOWN
    try { timeoutCountdown.cancel() } catch(ignored: Exception){}

    val mediaPlayer: MediaPlayer = MediaPlayer.create(this, R.raw.cping)
    mediaPlayer.start()

    index += 1
    if(setAnswer == thisButton){
        score += 1
    }

    if(index < 11){
        playNextSound()
    } else {
        showResults()
    }
}

If you are keen to use a Handler /Runnable situation instead which is really overkill if just for this use, do let me know and I'll add it in.

EDIT: Using this implementation there is no need for a while loop anymore; you're using the functions and the event trigger ( onClickListener or CountDownTimer ) as the control flow.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM