Kotlin: How to delay code in Android without making the UI freeze - kotlin

I am trying to delay code in Kotlin I have tried
Thread.sleep(1000)
But its freezes the UI.
Does somebody know why this is happening
And how to delay without freezing the UI?

What went wrong
Usage Thread.sleep(...)
Thread.sleep causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system.
For the OP (Original Poster / Asker)'s clarification:
It freezes the UI, does somebody know why this is happening?
As mentioned above from the official documentation of Java, you are experiencing a some sort of freezing in the UI because you have called it in the Main Thread.
Main Thread or if you are doing your stuff in Android, it is often called the UI Thread:
On the Android platform, applications operate, by default, on one thread. This thread is called the UI thread. It is often called that because this single thread displays the user interface and listens for events that occur when the user interacts with the app.
Without using the help of multi-threading APIs (Such as Runnable, Coroutines, RxJava), you will automatically be invoking Thread.sleep(1000) on the UI Thread that is why you are experiencing such "UI Freezing" experience because, other UI Operations are blocked from accessing the thread since you have invoke a suspension on it.
And how to delay without freezing the ui?
Harness the power of available APIs for multi-threading, so far it's good to start with the following options:
1. Runnable
In Java
// Import
import android.os.Handler;
// Use
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do something after 1000ms
}
}, 1000);
In Kotlin
// Import
import android.os.Handler;
// Use
val handler = Handler()
handler.postDelayed({
// do something after 1000ms
}, 1000)
2. Kotlin Coroutines
// Import
import java.util.*
import kotlin.concurrent.schedule
// Use
Timer().schedule(1000){
// do something after 1 second
}
3. RxJava
// Import
import io.reactivex.Completable
import java.util.concurrent.TimeUnit
// Use
Completable
.timer(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io()) // where the work should be done
.observeOn(AndroidSchedulers.mainThread()) // where the data stream should be delivered
.subscribe({
// do something after 1 second
}, {
// do something on error
})
Amongst the three, currently, RxJava is the way to go for multi threading and handling vast amount of data streams in your application. But, if you are just starting out, it is good to try out the fundamentals first.
References
https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html
https://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/
https://github.com/ReactiveX/RxJava
https://github.com/Kotlin/kotlinx.coroutines

You can use Handler object https://developer.android.com/reference/android/os/Handler.
val handler = Handler()
val runnable = Runnable {
// code which will be delayed
}
handler.postDelayed(runnable, 1000)
1000 is time in miliseconds, you should replace it with your value.

If you don't want to freeze the UI, you need to execute your code off of the MainThread.
There are a lot of way of doing it. Some examples:
Thread
Thread {
Thread.sleep(1000)
// Your code
}.start()
Rx
You need https://github.com/ReactiveX/RxJava
Flowable.timer(1000, TimeUnit.MILLISECONDS)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe {
// Your code
}
Kotlin coroutine
GlobalScope.launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
reference: https://kotlinlang.org/docs/reference/coroutines-overview.html
Documentations:
https://developer.android.com/guide/components/processes-and-threads
https://developer.android.com/topic/performance/threads
https://developer.android.com/training/multiple-threads/communicate-ui

if you are looking at delaying the code on a background thread and update the UI later kotlin coroutines come in handy check below
Timer().schedule(2000){
CoroutineScope(Main).launch {
withContext(Main){
//run UI related code
//will be executed after the timeout
}
}
}

GlobalSocpe.launch(Dispatchers.MAIN){
delay(5000)
}
this is the code part you asked for. But for your solution, first understand
launch
and
async
Similarly you should understand other values of
Dispatchers

Kotlin
Delayed code on UI Thread with Coroutines from a Fragment
Timer().schedule(1000) {
activity?.runOnUiThread {
// do something after 1000ms
}
}
If you get this Exception
java.lang.IllegalStateException: Method
setCurrentState must be called on the main thread
Handler is Deprecated

Thread.sleep(1000);
Causes the currently executing thread to sleep (temporarily cease
execution) for the specified number of milliseconds, [...]
see https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long)
If you call this on the UI thread, which is the default thread your code runs on, it will stop and wait.
In pure Kotlin you should use a coroutine:
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
If you are programming an Android app you can use a Handler and Androidx for especially nice syntax:
Handler().postDelayed( 1000 ) { doSomething() }

Use this extension:
//extension:
fun GlobalScope.runDelayedUITask(delay: Long, task: () -> Unit) {
launch(Dispatchers.IO) {
delay(delay)
launch(Dispatchers.Main) {
task()
}
}
}
//usage:
GlobalScope.runDelayedUITask(1000) {
//Your task...
}

Related

How to cancel kotlin coroutine with potentially "un-cancellable" method call inside it?

I have this piece of code:
// this method is used to evaluate the input string, and it returns evaluation result in string format
fun process(input: String): String {
val timeoutMillis = 5000L
val page = browser.newPage()
try {
val result = runBlocking {
withTimeout(timeoutMillis) {
val result = page.evaluate(input).toString()
return#withTimeout result
}
}
return result
} catch (playwrightException: PlaywrightException) {
return "Could not parse template! '${playwrightException.localizedMessage}'"
} catch (timeoutException: TimeoutCancellationException) {
return "Could not parse template! (timeout)"
} finally {
page.close()
}
}
It should throw exception after 5 seconds if the method is taking too long to execute (example: input potentially contains infinite loop) but it doesent (becomes deadlock I assume) coz coroutines should be cooperative. But the method I am calling is from another library and I have no control over its computation (for sticking yield() or smth like it).
So the question is: is it even possible to timeout such coroutine? if yes, then how?
Should I use java thread insted and just kill it after some time?
But the method I am calling is from another library and I have no control over its computation (for sticking yield() or smth like it).
If that is the case, I see mainly 2 situations here:
the library is aware that this is a long-running operation and supports thread interrupts to cancel it. This is the case for Thread.sleep and some I/O operations.
the library function really does block the calling thread for the whole time of the operation, and wasn't designed to handle thread interrupts
Situation 1: the library function is interruptible
If you are lucky enough to be in situation 1, then simply wrap the library's call into a runInterruptible block, and the coroutines library will translate cancellation into thread interruptions:
fun main() {
runBlocking {
val elapsed = measureTimeMillis {
withTimeoutOrNull(100.milliseconds) {
runInterruptible {
interruptibleBlockingCall()
}
}
}
println("Done in ${elapsed}ms")
}
}
private fun interruptibleBlockingCall() {
Thread.sleep(3000)
}
Situation 2: the library function is NOT interruptible
In the more likely situation 2, you're kind of out of luck.
Should I use java thread insted and just kill it after some time?
There is no such thing as "killing a thread" in Java. See Why is Thread.stop deprecated?, or How do you kill a Thread in Java?.
In short, in that case you do not have a choice but to block some thread.
I do not know a solution to this problem that doesn't leak resources. Using an ExecutorService would not help if the task doesn't support thread interrupts - the threads will not die even with shutdownNow() (which uses interrupts).
Of course, the blocked thread doesn't have to be your thread. You can technically launch a separate coroutine on another thread (using another dispatcher if yours is single-threaded), to wrap the libary function call, and then join() the job inside a withTimeout to avoid waiting for it forever. That is however probably bad, because you're basically deferring the problem to whichever scope you use to launch the uncancellable task (this is actually why we can't use a simple withContext here).
If you use GlobalScope or another long-running scope, you effectively leak the hanging coroutine (without knowing for how long).
If you use a more local parent scope, you defer the problem to that scope. This is for instance the case if you use the scope of an enclosing runBlocking (like in your example), which makes this solution pointless:
fun main() {
val elapsed = measureTimeMillis {
doStuff()
}
println("Completely done in ${elapsed}ms")
}
private fun doStuff() {
runBlocking {
val nonCancellableJob = launch(Dispatchers.IO) {
uncancellableBlockingCall()
}
val elapsed = measureTimeMillis {
withTimeoutOrNull(100.milliseconds) {
nonCancellableJob.join()
}
}
println("Done waiting in ${elapsed}ms")
} // /!\ runBlocking will still wait here for the uncancellable child coroutine
}
// Thread.sleep is in fact interruptible but let's assume it's not for the sake of the example
private fun uncancellableBlockingCall() {
Thread.sleep(3000)
}
Outputs something like:
Done waiting in 122ms
Completely done in 3055ms
So the bottom line is either live with this long thing potentially hanging, or ask the developers of that library to handle interruption or make the task cancellable.

Kotlin/Native: How to perform blocking calls asynchronously?

As of now, Kotlin/Native is single-threaded. Therefore, the following code will become blocked by sleep:
coroutineScope {
launch { plaform.posix._sleep(100000) }
launch { println("Hello") }
}
However, it has a novel concurrency mechanism called Workers. Yet, even with worker the main thread is going to be blocked by long-running posix call:
coroutineScope {
launch { Worker.start().execute(TransferMode.SAFE, { }, { plaform.posix._sleep(100000) }).consume{ } }
launch { println("Hello") }
}
Both of the snippets above will never print Hello.
What is the correct way to perform a series of expensive blocking calls asynchronously?
There is a multithreaded version of kotlin coroutines for K/N, which lives on a separate branch currently: native-mt.
You could use Dispatchers.Default to offload tasks to the background thread
So, the problem is that I used the consume method, which blocks the main thread.
Instead, you need to execute the worker, and then check manually whether it finished:
val job = Worker.start().execute(TransferMode.SAFE, { }) { plaform.posix._sleep(100000) }
...
if (job.state == FutureState.Computed)
job.result

Kotlin coroutines - how to run in background and use result in the caller thread?

The main idea is to have non-suspend function runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) which run some work asynchronously in background (another thread) and after work is done - run callback in the caller thread (thread that launched runInBackgroundAndUseInCallerThread).
Below I wrote an example code, but I'm not sure how correct it is and whether it is possible at all. With the println("1/2/3/...") I marked the desired call order.
getDispatcherFromCurrentThread - if is possible to implement this function, then solution can be used, but I don't know how to implement it and is it right to do it like that at all.
Therefore, please do not consider it as the only solution.
import kotlinx.coroutines.*
import kotlin.concurrent.thread
fun main() {
println("1")
runInBackgroundAndUseInCallerThread {
println("4")
println("Hello ${it.someField} from ${Thread.currentThread().name}") // should be "Hello TestField from main"
}
println("2")
thread(name = "Second thread") {
runInBackgroundAndUseInCallerThread {
println("5")
println("Hello ${it.someField} from ${Thread.currentThread().name}") // should be "Hello TestField from Second thread"
}
}
println("3")
Thread.sleep(3000)
println("6")
}
fun runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) {
val dispatcherFromCallerThread: CoroutineDispatcher = getDispatcherFromCurrentThread()
CoroutineScope(Dispatchers.IO).launch {
val result: SomeModel = getModelResult()
launch(dispatcherFromCallerThread) { callback(result) }
}
}
data class SomeModel(val someField: String)
suspend fun getModelResult(): SomeModel {
delay(1000)
return SomeModel("TestField")
}
fun getDispatcherFromCurrentThread(): CoroutineDispatcher {
// TODO: Create dispatcher from current thread... How to do that?
}
Unless the thread is designed to work as a dispatcher there isn't a universal way to make it do so.
The only way which comes to mind is the fact that runBlocking is re-entrant and will create an event-loop in the existing thread, however it will block all non-coroutine code from executing on that thread until it completes.
This ends up looking like:
fun runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) {
callback(runBlocking(Dispatchers.IO) {
getModelResult()
})
}
dispatcher really is a coroutineContext and it is meaningful when used inside a scope
thus if you want pass dispatcher of parent scope to child scope you can do it.
GlobalScope.launch {
val dispatcher = this.coroutineContext
CoroutineScope(dispatcher).launch {
}
}
therefor getDispatcherFromCurrentThread should be like this.
fun getDispatcherFromCurrentThread(scope: CoroutineScope): CoroutineContext {
return scope.coroutineContext
}
and
GlobalScope.launch {
val dispatcher = getDispatcherFromCurrentThread(this)
CoroutineScope(dispatcher).launch {
}
}
which run some work asynchronously in background (another thread) and after work is done - run callback in the caller thread
First try to answer this question: what is the calling thread supposed to do while the background work is in progress?
Clearly it can't go on to the next line of your code, which is supposed to run after finishing the background work.
You also don't want it to block and wait.
What code should it run, then?
And the only reasonable answer is as follows: the calling thread should, at its topmost level of execution (entry-point function), run an infinite event loop. The code in your question should be inside an event handler submitted to the event loop. At the point you want to wait for the background work, the handler must return so the thread can go on handling other events, and you must have another handler ready to submit when the background work is done. This second handler, corresponding to your callback, is called the continuation and Kotlin provides it automatically. You don't in fact need your own callback.
However, now the most sensitive issue arises: how will you submit the continuation to the event loop? This is not something you can abstract over, you must use some API specific to the event loop in question.
And this is why Kotlin has the notion of a Dispatcher. It captures the case-specific concern of dispatching continuations to the desired thread. You seem to want to solve it without the need to write a dispatcher dedicated to each specific event loop, and unfortunately this is impossible.

Why is Kotlin ignoring the delay(timeMillis: Long) function

The context
Following the Kotlin Coroutines basics guide at this point
using this code
fun coroutinesAreLightWeight()
{
runBlocking {
repeat(100_000) {
launch {
delay(1000L)
print("$it, ")
}
}
}
}
Issue
When I run the program on my computer it prints out all the digits in one go instead of waiting for 1 second to elapse before printing the next digit. This behaviour is the same when running the exact code as seen in the kotlin guide. It seems like the delay() function is being ignored
At first this block of code worked fine but then it stopped working as intended. I am using IntelliJ 2019.2.1 with kotlin version 1.3.50 and I have tried restarting the program but that didn't solve my problem.
Here is how the whole class looks like
class CoroutinesBasics
{
fun ...
fun ...
fun coroutinesAreLightWeight()
{
runBlocking {
repeat(100_000) {
launch {
delay(1000L)
print("$it, ")
}
}
}
}
}
and the coroutinesAreLightWeight() function is called like this
fun main()
{
CoroutineBasics().apply{
....
....
coroutinesAreLightWeight()
}
}
Can anyone point me to what is going on? Is this a Kotlin bug?
Kotlin dependencies
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
I'll take another angle to answer this.
The example is given in a specific context. Namely, "coroutines are not like threads". The goal of the example is not to demonstrate how to print numbers with delays, but to demonstrate that coroutines, unlike threads, can be launched in thousands simultaneously. And that's exactly what this code is doing. It submits them all, then executes them all.
You may ask then, why they are all sequential? Shouldn't they run concurrently?
For that, let's print the thread name:
repeat(100_000) {
launch {
delay(100L)
println("$it, ${Thread.currentThread().name}")
}
}
You'll quickly see the reason: 99999, main
Since you're using runBlocking, all your coroutines are executed by a single thread.
We can change it, though:
runBlocking {
repeat(100_000) {
launch(Dispatchers.Default) {
delay(100L)
println("$it, ${Thread.currentThread().name}")
}
}
}
By using Dispatchers.Default, we're running our coroutines on a default thread pool. And then the results become much less predictable:
98483, DefaultDispatcher-worker-6
99898, DefaultDispatcher-worker-5
99855, DefaultDispatcher-worker-1
99706, DefaultDispatcher-worker-2
The default thread pool starts with 2 threads, and goes up to number of CPU cores by default. You can look at createDefaultDispatcher() for the actual implementation.
Regarding Thread.sleep(), you should know a few things:
Never use Thread.sleep() inside coroutine
Never use Thread.sleep() inside coroutine
IntelliJ will even warn you to never use Thread.sleep() inside coroutine
Let's look at the following example to understand why:
repeat(100_000) {
launch {
Thread.sleep(100)
println("$it, ${Thread.currentThread().name}")
}
}
You may assume what you're saying is "don't do anything in this block for 100ms".
But what you're actually saying is "don't do literally anything for 100ms".
Since launch will execute on context it got from runBlocking, and runBlocking is a single threaded context, you block executions of all coroutines.
This is the intended behavior as far as I know because coroutines are working simultaneously, so your code will only wait for 1 second for all coroutines that are currently working.
A good talk that I recommend about the coroutines is:
KotlinConf 2017 - Introduction to Coroutines by Roman Elizarov
And it has the exact same example in the slides :)
if you want them to wait you should move the repeat to outside the 'runBlocking'

Kotlin Coroutines with timeout

I'm currently writing a test-function which should run a block or (when a certain timeout is reached) throws an exception.
I was trying this with Coroutines in Kotlin but ended up with a mixture of Coroutines and CompletableFuture:
fun <T> runBlockWithTimeout(maxTimeout: Long, block: () -> T ): T {
val future = CompletableFuture<T>()
// runs the coroutine
launch { block() }
return future.get(maxTimeout, TimeUnit.MILLISECONDS)
}
This works, but I'm not sure if this is the intended way to solve that problem in kotlin.
I also tried other approaches:
runBlocking {
withTimeout(maxTimeout) {
block()
}
}
But this seems not to work as soon as the block calls e.g. Thread.sleep(...)
So is the CompletableFuture approach the way to go or is there a better one?
update 1
What I want to achieve:
Async Integration-Test code (like receiving data from RabbitMq) should be tested somehow like this:
var rabbitResults: List = ... // are filled async via RabbitListeners
...
waitMax(1000).toSucceed {
assertThat(rabbitResults).hasSize(1)
}
waitMax(1000).toSucceed {
assertThat(nextQueue).hasSize(3)
}
...
withTimeout { ... } is designed to cancel the ongoing operation on timeout, which is only possible if the operation in question is cancellable.
The reason it works with future.get(timeout, unit) is because it only waits with timeout. It does not actually cancel or abort in any way your background operation which still continues to execute after timeout had elapsed.
If you want to mimick similar behavior with coroutines, then you should wait with timeout, like this:
val d = async { block() } // run the block code in background
withTimeout(timeout, unit) { d.await() } // wait with timeout
It works properly because await is a cancellable function which you can verify by reading its API documentation.
However, if you want to actually cancel the ongoing operation on timeout, then then you should implement your code in asyncronous and cancellable way. Cancellation is cooperative, so, to start, the underlying library that you are using in your code has to provide asynchronous API that supports cancellation of ongoing operation.
You can read more about cancellation and timeouts in the corresponding section of the coroutines guide and watch the KotlinConf's Deep Dive into Coroutines on how to integrate coroutines with asynchronous libraries.