0

In my application the user is prompted with an exercise and he has 5 seconds to solve it, if he does not respond in time, the next exercise should be shown.
My question is: What would be the best way to implement such a behaviour in Android?

I have first tried it with a CountDownTimer but for some reason the CountDownTimer.cancel() does not cancel the timer.

My second attempt works, (see below) but it contains a buisy wait and I don't know if that is such a good pattern.

for (int i = 0; i < NUM_EXERCISES; i++) {
    // show a new fragment with an activity

    fragmentManager.beginTransaction()
            .replace(R.id.exercise_container, getNextExercise())
            .commit();

    // I create a thread and let it sleep for 5 seconds, and then I wait busily
    // until either the thread is done or the user answers and I call future.cancel()
    // in the method that is responsible for handling the userinput

    future = es.submit(()->{
        Thread.sleep(5000);
        return null;
    });

    while (!future.isDone()) { }
}

It works like this: I create a Java Future which task it is to just wait 5 seconds and in the callback method, that is responsible for handling the userinput I call future.cancel(), so the while loop can be left and the code gets executed further, meaning the for loop does another iteration.
If the user does not respond in time, the while loop is left after 5 seconds, ensuring that the user does not spend too much time on one exercise.

Feel free to ask for further clarification if needed. Thank you in advance!

Neuron
  • 5,141
  • 5
  • 38
  • 59
J.Doe
  • 109
  • 1
  • 6

1 Answers1

0

The timer should be canceled in your code. try this :

        private var countDownTimer: CountDownTimer? = null
        countDownTimer = object : CountDownTimer(10000, 1000) {
        override fun onFinish() {}

        override fun onTick(millisUntilFinished: Long) {
            Log.d("millisUntil", millisUntilFinished.toString())
            if ((millisUntilFinished / 1000) <= 5) {
                countDownTimer?.cancel()
            }
        }
    }.start()

It is a 10sec timer and it cancels at 5sec by calling countDownTimer?.cancel().

Meet Prajapati
  • 416
  • 5
  • 9
  • the timer would be a perfect choice for the usage you described. – Meet Prajapati Oct 16 '21 at 17:53
  • "The timer should be canceled in your code." What do you mean by that? Furthermore, I cannot cancel the timer in the `onTick()` method, I have to cancel the timer in the callback method that is handling the userinput. But, for some reason, that doesn't work. – J.Doe Oct 16 '21 at 19:54
  • This is just an example. you can cancel it outside the onTick method as well. For more control, you can put a counter inside a view model and observe it so you will know when it stops. inside the observer navigate to another fragment. – Meet Prajapati Oct 16 '21 at 20:09
  • The problem is, that the `CountDownTimer` *needs* to be canceled from the same thread as it has started. If I try to call `CountDownTimer.cancel()` from another thread, it doesn't work. If I call the `CountDownTimer` from the main thread, I don't have some kind of `await()` method, so how do I wait for the CDTimer to finish? The `for` loop would immediately go into another iteration, replacing the current exercise. On the other hand, if I create a thread executing the `CountDownTimer.start()` method, it does not terminate after the timer is at 0. – J.Doe Oct 17 '21 at 17:08