'how to use Coroutine in kotlin to call a function every second

i just created an app where my function getdata() call every second to fetch new data from server and updateui() function will update view in UI i don't use any asynctask or coroutine in my app i wants to do this please tell me how i can do that.

here's my code...

private fun getdata(){
        try {
            val api = RetroClient.getApiService()
            call = api.myJSON
            call!!.enqueue(object : Callback<ProductResponse> {
                override fun onResponse(
                    call: Call<ProductResponse>,
                    response: Response<ProductResponse>
                ) {
                    if (response.isSuccessful) {
                        productList = response.body()!!.data
                        for (list in productList) {
                            if (list.BB.equals("AAA")) {
                                aProductList.add(list)
                            }
                        }
                        if (recyclerView.adapter != null) {
                            eAdapter!!.updatedata(aProductList)
                        }
                        updateui()
                    }
                }

                override fun onFailure(call: Call<ProductResponse>, t: Throwable) {
                    println("error")
                }
            })
        } catch (ex: Exception) {
        } catch (ex: OutOfMemoryError) {
        }
Handler().postDelayed({
            getdata()
        }, 1000)
}


private fun updateui() {
        try {
            //some code to handel ui
 } catch (e: NumberFormatException) {

        } catch (e: ArithmeticException) {

        } catch (e: NullPointerException) {

        } catch (e: Exception) {

        }
    }


Solution 1:[1]

it's not advisable to hit the server every second. if you need to get data continuously try the socket. Because some times your server takes more than a few seconds to respond to your request. Then all your requests will be in a queue..if you still need to try with this.

fun repeatFun(): Job {
    return coroutineScope.launch {  
        while(isActive) {
            //do your network request here
            delay(1000)
        }
    }
}

//start the loop
val repeatFun = repeatRequest()

//Cancel the loop
repeatFun.cancel()

Solution 2:[2]

To run a function every second with coroutines:

val scope = MainScope() // could also use an other scope such as viewModelScope if available
var job: Job? = null

fun startUpdates() {
    stopUpdates()
    job = scope.launch {
        while(true) {
            getData() // the function that should be ran every second
            delay(1000)
        }
    }
}

fun stopUpdates() {
    job?.cancel()
    job = null
}

However, if getData() only starts a network request and doesn't wait for its completion, this might not be a very good idea. The function will be called a second after it finished, but because the network request is done asynchronously it may be scheduled way too much.
For example if the network request takes 5 seconds, it will have been started 4 more times before the first one even finished!

To fix this, you should find a way to suspend the coroutine until the network request is done.
This could be done by using a blocking api, then pass Dispatchers.IO to the launch function to make sure it's done on a background thread.

Alternatively you could use suspendCoroutine to convert a callback-based api to a suspending one.


Update - Lifecycle scope

Inside a component with a Android Lifecycle you could use the following code to automate repeating ui updates:

fun startUpdates() {
    val lifecycle = this // in Activity
    val lifecycle = viewLifecycleOwner // in Fragment

    lifecycle.lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            // this block is automatically executed when moving into
            // the started state, and cancelled when stopping.
            while (true) {
                getData() // the function to repeat
                delay(1000)
            }
        }
    }
}

This code requires the current androidx.lifecycle:lifecycle-runtime-ktx dependency.

The above remark about async, blocking or suspending code inside getData() still applies.

Solution 3:[3]

I ended up doing like this with an extension function:

fun CoroutineScope.launchPeriodicAsync(repeatMillis: Long, action: () -> Unit) = this.async {
  while (isActive) {
    action()
    delay(repeatMillis)
  }
}

then call it like:

val fetchDatesTimer = CoroutineScope(Dispatchers.IO)
  .launchPeriodicAsync(TimeUnit.MINUTES.toMillis(1)) {
    viewModel.fetchDeliveryDates()
  }

and cancel it like:

fetchDatesTimer.cancel()

Solution 4:[4]

For those who are new to Coroutine

add Coroutine in Build.gradle

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'

To create a repeating Job

    /**
     * start Job
     * val job = startRepeatingJob()
     * cancels the job and waits for its completion
     * job.cancelAndJoin()
     * Params
     * timeInterval: time milliSeconds 
     */
    private fun startRepeatingJob(timeInterval: Long): Job {
        return CoroutineScope(Dispatchers.Default).launch {
            while (NonCancellable.isActive) {
                // add your task here
                doSomething()
                delay(timeInterval)
            }
        }
    }

To start:

  Job myJob = startRepeatingJob(1000L)

To Stop:

    myJob .cancel()

Solution 5:[5]

My solution in Kotlin inside MainViewModel

fun apiCall() {
       viewModelScope.launch(Dispatchers.IO) {
         while(isActive) {
            when(val response = repository.getServerData()) {
                is NetworkState.Success -> {
                    getAllData.postValue(response.data)
                }
                is NetworkState.Error -> [email protected] = false
            }

            delay(1000)
        }
    }
}


sealed class NetworkState<out R> {
    data class Success<out T>(val data: T): NetworkState<T>()
    data class Error(val exception: String): NetworkState<Nothing>()
    object Loading: NetworkState<Nothing>()
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 vignesh
Solution 2
Solution 3 nilsi
Solution 4 Hitesh Sahu
Solution 5 Thiago