How to Call a Function After Delay in Kotlin

How to call a function after delay in Kotlin?

You can use Schedule

inline fun Timer.schedule(
delay: Long,
crossinline action: TimerTask.() -> Unit
): TimerTask (source)

example (thanks @Nguyen Minh Binh - found it here: http://jamie.mccrindle.org/2013/02/exploring-kotlin-standard-library-part-3.html)

import java.util.Timer
import kotlin.concurrent.schedule

Timer("SettingUp", false).schedule(500) {
doSomething()
}

How to set delay in Kotlin?

there are some ways:

1- use Handler(base on mili-second)(Deprecated):

println("hello")
Handler().postDelayed({
println("world")
}, 2000)

2- by using Executors(base on second):

println("hello")
Executors.newSingleThreadScheduledExecutor().schedule({
println("world")
}, 2, TimeUnit.SECONDS)

3- by using Timer(base on mili-second):

println("hello")
Timer().schedule(2000) {
println("world")
}

How to call a method after a delay in Android

Kotlin

Handler(Looper.getMainLooper()).postDelayed({
//Do something after 100ms
}, 100)

Java

final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);

Kotlin: call a function every second

Problem: Timer class uses a background thread with a queue to queue and execute all tasks sequentially. From your code, because you update UI (changing TextView content in minusOneSecond function). That why the app throws the following exception and make your app crash.

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.

Solution: There are many ways to achieve your task, but I prefer using post() and postDelayed() method from Handler class. Because it's simple and easy to understand.

val mainHandler = Handler(Looper.getMainLooper())

mainHandler.post(object : Runnable {
override fun run() {
minusOneSecond()
mainHandler.postDelayed(this, 1000)
}
})

Update: From author's comment about how to pause/resume the task from Handler. Here is an example.

class MainActivityKt : AppCompatActivity() {

lateinit var mainHandler: Handler

private val updateTextTask = object : Runnable {
override fun run() {
minusOneSecond()
mainHandler.postDelayed(this, 1000)
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Your logic code
...
mainHandler = Handler(Looper.getMainLooper())
}

override fun onPause() {
super.onPause()
mainHandler.removeCallbacks(updateTextTask)
}

override fun onResume() {
super.onResume()
mainHandler.post(updateTextTask)
}

fun minusOneSecond() {
if secondsLeft > 0 {
secondsLeft -= 1
seconds_thegame.text = secondsLeft.toString()
}
}
}

I want to Stop my function to execute, which is written in post delay, whenever I interrupt it with textChangedListner In Kotlin

Best way to use coroutines for such a case in kotlin.
If you don't know coroutines or don't want to use it. Then you can use Timer.

 private Timer timer = new Timer();
private final long DELAY = 500; // Milliseconds

override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int){
timer.cancel();
timer = new Timer();
timer.schedule(
new TimerTask() {
@Override
public void run() {
// TODO: Do what you need here.
val lengthoftext = searchCompany.text.length
mycompanies.clear()
callforapi(s.toString())
}
},
DELAY
);
}
}
}

Android Kotlin Coroutines - Call Api Every X Seconds on Background

You could add a loop with a delay in your use case:

class GetCoinsUseCase @Inject constructor(
private val repository: CoinRepository
) {
operator fun invoke(): Flow<Resource<List<Coin>>> = flow {
while (currentCoroutineContext().isActive) {
try {
emit(Resource.Loading<List<Coin>>())
val coins = repository.getCoins().map { it.toCoin() }
emit(Resource.Success<List<Coin>>(coins))

} catch(e: HttpException) {
emit(Resource.Error<List<Coin>>(e.localizedMessage ?: "An unexpected error occured"))
} catch(e: IOException){
emit(Resource.Error<List<Coin>>("Couldn't reach to server. Check your internet connection."))
}

// Wait until next request
delay(3000)
}
}
}

You could also move the loop and delay call around depending on the precise functionality you are looking for. For example, to stop once there is an error you could do

class GetCoinsUseCase @Inject constructor(
private val repository: CoinRepository
) {
operator fun invoke(): Flow<Resource<List<Coin>>> = flow {
emit(Resource.Loading<List<Coin>>())
try {
while (currentCoroutineContext().isActive) {
val coins = repository.getCoins().map { it.toCoin() }
emit(Resource.Success<List<Coin>>(coins))

// Wait until next request
delay(3000)
}
} catch(e: HttpException) {
emit(Resource.Error<List<Coin>>(e.localizedMessage ?: "An unexpected error occured"))
} catch(e: IOException){
emit(Resource.Error<List<Coin>>("Couldn't reach to server. Check your internet connection."))
}
}
}

This should already naturally "run in the background" as long as your app is running and you are not cancelling the coroutine manually when going in the background.

Trying to execute line after delay in Android Studio with Kotlin

Doing this way, you're asking to display 5 strings but with the same delay.

To my mind, you have to use a CountDownTimer to display another piece of text following a regular interval.

Here is a sample code

class Ball (val Ball: TextView, val messagesList: List<String>){

private var index = 0
fun textChange(interval: Long) {
val time = interval * messagesList.size
val timer = object: CountDownTimer(time, interval) {
override fun onTick(millisUntilFinished: Long) {
Ball.append(" " +messagesList[index++])
}

override fun onFinish() {
//nothing to do
}
}
timer.start()
}
}

class MainActivity : AppCompatActivity() {
var messageList = mutableListOf<String>("Hello", "World", "How are you ?")

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

fun playButtonPressed(view:View){
// will update the text every second during until the list is empty
Ball(textView, messageList).textChange(1000)
}
}

cancelling a suspend function in kotlin if the same function is called again

This kind of event processing is usually handled using reactive streams and is often named the debounce operator. It exists in both ReactiveX (Debounce) and in Kotlin flows (debounce()).

As you already use coroutines, I suggest going with Kotlin flows. Please see the example below:

private val flow = MutableStateFlow(0)

suspend fun main() = coroutineScope {
launch {
// consumer of events
flow
.debounce(2.seconds)
.collect { println(it) }
}

// producer
delay(100)
addCounter() // 1
delay(500)
addCounter() // 2, ignore 1
delay(500)
addCounter() // 3, ignore 2
delay(2500) // show 3
addCounter() // 4
delay(500)
addCounter() // 5, ignore 4
delay(3000) // show 5
}

fun addCounter() {
flow.value++
}

It shows only 3 and 5, because all other events were "cancelled" by subsequent events that came too fast.



Related Topics



Leave a reply



Submit