Home > Software engineering >  How to wait for an async task to complete that starts in onResume() while the user is allowed to cli
How to wait for an async task to complete that starts in onResume() while the user is allowed to cli

Time:10-24

Android app programming:

So let's say I trigger an asynchronous task in the onResume() block of my fragment that has 2 Java callback methods on completion - onSuccess() and onFailure(). Meanwhile, there's a button on the screen that the user can click any time. The catch is, on button click I need to wait for the earlier asynchronous task to complete before executing button click code.

I need to show a progress bar on button click while the asynchronous task completes (if it hasn't completed already), but not sure how to code it such that on button click I am aware that the button has been clicked and also the async task hasn't completed yet and I need to wait for it to complete before proceeding further.

I am thinking I need to use LiveData and/or Kotlin coroutines in this process, but not sure how to proceed with it.

Can anyone please guide me in the right direction on this? I am trying my best to understand asynchronous programming.

CodePudding user response:

If you don't use coroutines, etc. right now then you can implement this easily with just a few booleans and ifs. Assuming all onSuccess(), onFailure() and onBtnClick() are invoked on the main thread, this should do the trick:

private var firstTaskRunning = false
private var scheduledSecondTask = false

fun startFirstTask() {
    firstTaskRunning = true
    // start first task
}

fun onSuccess() {
    onFirstTaskFinished()
}

fun onFailure() {
    onFirstTaskFinished()
}

fun onFirstTaskFinished() {
    firstTaskRunning = false
    
    if (scheduledSecondTask) {
        scheduledSecondTask = false
        hideBtnProgress()
        secondTask()
    }
}

fun onBtnClick() {
    if (firstTaskRunning) {
        scheduledSecondTask = true
        showBtnProgress()
    } else {
        secondTask()
    }
}

You should also think about other corner cases like for example: first task was scheduled while it is already running; button is clicked while second task is running, etc.

CodePudding user response:

Define a lateinit var at the top of your Activity, private lateinit var asyncJob: Job

override fun onResume() {
    super.onResume()
    asyncJob = lifecycleScope.launch {
        // Do the work
    }
}

fun onButtonClicked() {
    while (asyncJob.isActive) showProgressIndicator()
    hideProgressIndicator()
    // Handle the button click
}

Keep in mind that lifecycleScope's default thread is main, if you want a coroutine to run on a background thread, provide an adequate dispatcher to the launch(dispatcher) {...} function.

If you're using a Fragment instead of an Activity use viewLifecycleOwner.lifecycleScope.launch instead of lifecycleScope.launch

lifecycleScope is an extension function and can be found in androidx.lifecycle:lifecycle-runtime-ktx:version

  • Related