import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
val numbers: StateFlow<Int> = (1..100).asFlow()
.onEach { delay(100) }
.let {
runBlocking {
it.stateIn(this)
}
}
fun main(){
println("hello")
println(numbers.value)
println("bye")
}
I expect that main function finish only in 100ms (wait for first emission)
but second print happens when all items emitted (takes about 100*100 ms) and also prints last item instead of first one!
am I missing something or it is a bug ?
That’s expected behaviour when you use runBlocking, because runBlocking won’t return until all of its child jobs have completed.
In other words, the numbers property won’t return a value until the entire flow has terminated. This is because calling stateIn(scope) launches a job inside the scope that collects all the items from the flow. You can see where this happens in the source code.
If you want to allow the numbers flow to emit values concurrently with your main function, you'll need to use a scope in which both functions can run together. For example, you could call runBlocking in the main function, and pass the scope as a receiver for the numbers property:
val CoroutineScope.numbers: StateFlow<Int> get() = (1..100).asFlow()
.onEach { delay(100) }
.let {
it.stateIn(this)
}
fun main() = runBlocking {
println("hello")
println(numbers.value)
println("bye")
}
So I have this function where I can emit values with flow but I need to send values periodically and so I used:
fun hereIsAFunction(): Flow<Type> = flow {
Handler.postDelayed({
//This is in Runnable and I can't emit values
emit(value) //Error 'Suspension function can only be called within Coroutine body
}, 1000)
usingOtherFunction()
}
I don't want to block the function 'usingOtherFunction()', that's why I'm using a runnable
Question: Is there any way to emit values with Flow with periodically events? If yes, what should I look into?
According to your comment that you want to do something in parallel, you can launch 2 coroutines in a scope. They will run independent to each other:
fun hereIsAFunction(): Flow<Type> = flow {
coroutineScope {
launch {
(0..100).forEach {
delay(1000)
emit(...)
}
}
launch {
usingOtherFunction()
}
}
}
Flows are built on top of coroutines. You can use the delay(time) method of coroutines to delay the execution.
More details here: https://developer.android.com/kotlin/flow#create
Here's my ViewModel
class MainViewModel(repository: MainActivityRepo) : ViewModel() {
val isLoading: MutableLiveData<Boolean> = MutableLiveData()
init {
isLoading.value = false
android.os.Handler().postDelayed({
isLoading.value = true
Timber.d("isCalled")
}, 5000L)
}
}
I debugged and checked and the log is working perfectly.
The first value of boolean is set correctly, while the second is not
On background thread, you can use post value instead of set value which will solve your problem!
As mentioned by Vikas you should use the postValue() method.
Handler().postDelayed({
isLoading.postValue(true)
Timber.d("isCalled")
}, 5000L)
I am trying to create Observable in kotlin .But its giving error unresolved reference on OnSubscribe method
fun getDisposableObserver(): Observable<Background> {
return Observable.create(object :Observable.OnSubscribe<Background> ->{})
}
I tried this snippet .It also does not work
Observable.create(object : ObservableOn.OnSubscribe<Int> {
override fun call(subscriber: Subscriber<in Int>) {
for(i in 1 .. 5)
subscriber.onNext(i)
subscriber.onCompleted()
}
})
What i am doing wrong ?,How can i create Observable?
If you want to control the items emission by your self, you can create an Observable with .create method, like this
Observable.create({ e: ObservableEmitter<String> -> e.onNext("") })
Observable.create(object: ObservableOnSubscribe<String> {
override fun subscribe(e: ObservableEmitter<String>) {
e.onNext("")
}
})
But in this case you will have to call onNext, onComplete, onError by your own.
But if you want a much simpler solution, you can create it like
Observable.just(1)
Observable.fromCallable { 1 }
Simple example with ObservableEmitter
val obs = Observable.create<Int> {
for(i in 1 .. 5)
it.onNext(i)
it.onComplete()
}
I don't know if you are using Architecture Components, but if i want to observe Background i think that MutableLiveData and LiveData could help
private val _background = MutableLiveData<Background>()
val background: LiveData<Background> = _background
fun editBackground(newBackground : Background) {
_background.postValue(newBackground)
}
Put this code inside a ViewModel or a Presenter.
Then in your View (Activity/Fragment) you can observe background in this way
viewModel.background.observe(this, Observer { newValue ->
})
As the title, is there any way to call a function after delay (1 second for example) in Kotlin?
There is also an option to use Handler -> postDelayed
Handler().postDelayed({
//doSomethingHere()
}, 1000)
Many Ways
1. Using Handler class
Handler().postDelayed({
TODO("Do something")
}, 2000)
2. Using Timer class
Timer().schedule(object : TimerTask() {
override fun run() {
TODO("Do something")
}
}, 2000)
// Shorter
Timer().schedule(timerTask {
TODO("Do something")
}, 2000)
// Shortest
Timer().schedule(2000) {
TODO("Do something")
}
3. Using Executors class
Executors.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
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()
}
You could launch a coroutine, delay it and then call the function:
/*GlobalScope.*/launch {
delay(1000)
yourFn()
}
If you are outside of a class or object prepend GlobalScope to let the coroutine run there, otherwise it is recommended to implement the CoroutineScope in the surrounding class, which allows to cancel all coroutines associated to that scope if necessary.
You have to import the following two libraries:
import java.util.*
import kotlin.concurrent.schedule
and after that use it in this way:
Timer().schedule(10000){
//do something
}
val timer = Timer()
timer.schedule(timerTask { nextScreen() }, 3000)
If you're using more recent Android APIs the Handler empty constructor has been deprecated and you should include a Looper. You can easily get one through Looper.getMainLooper().
Handler(Looper.getMainLooper()).postDelayed({
//Your code
}, 2000) //millis
If you are in a fragment with viewModel scope you can use Kotlin coroutines:
myViewModel.viewModelScope.launch {
delay(2000)
// DoSomething()
}
A simple example to show a toast after 3 seconds :
fun onBtnClick() {
val handler = Handler()
handler.postDelayed({ showToast() }, 3000)
}
fun showToast(){
Toast.makeText(context, "Its toast!", Toast.LENGTH_SHORT).show()
}
If you are looking for generic usage, here is my suggestion:
Create a class named as Run:
class Run {
companion object {
fun after(delay: Long, process: () -> Unit) {
Handler().postDelayed({
process()
}, delay)
}
}
}
And use like this:
Run.after(1000, {
// print something useful etc.
})
i suggest to use kotlin coroutine and if you want to cancel it. its simple and light weight.
fun repeatFun(): Job {
return coroutineScope.launch {
while(isActive) {
//do your work here
delay(1000)
}
}
}
//start the loop
val repeatFun = repeatRequest()
//Cancel the loop
repeatFun.cancel()
I recommended using SingleThread because you do not have to kill it after using. Also, "stop()" method is deprecated in Kotlin language.
private fun mDoThisJob(){
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({
//TODO: You can write your periodical job here..!
}, 1, 1, TimeUnit.SECONDS)
}
Moreover, you can use it for periodical job. It is very useful. If you would like to do job for each second, you can set because parameters of it:
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
TimeUnit values are: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS.
I use the following function(s):
fun <T> delayedAsyncTask(delayMs: Long = 0, task: () -> T): ScheduledFuture<T> {
return Executors
.newSingleThreadScheduledExecutor()
.schedule(Callable<T> { task() }, delayMs, TimeUnit.MILLISECONDS)
}
fun <T> asyncTask(task: () -> T) = delayedAsyncTask(0, task)
Here's a unit test for the delayed function. Use of the returned future is optional of course.
#Test
fun `delayed task work correctly`() {
val future = delayedAsyncTask(1000) {
"lambda returns hello world"
}
assertEquals(false, future.isDone)
Thread.sleep(1100)
assertEquals(true, future.isDone)
assertEquals("lambda returns hello world", future.get())
}
Another way to create a redundant job other than this; that does not require the function to be suspend.
val repeatableJob = CoroutineScope(Dispatchers.IO).launch {
while (true) {
delay(1000)
}
}
Cancel when you are done -
repeatableJob.cancel()