0

onNext method of publishSubject is calling continuously(in uneven time, approximately in 1 milliseconds) And requirement is to emit these item at every 1 second and data should not loss means should emit each item.

    publishSubject.onNext("Data1");
    publishSubject.onNext("Data2");
    publishSubject.onNext("Data3");
    publishSubject.onNext("Data4");
    publishSubject.onNext("Data5");
    publishSubject.onNext("Data6");
    publishSubject.onNext("Data7");

and so on... See Code Structure for Reference:

var publishSubject = PublishSubject.create<String>()
publishSubject.onNext(stateObject) // Executing at every milliseconds...


publishSubject
        /* Business Logic Required Here ?? */
        .subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe {
            // Should execute at every 1 second
        }

Please help, Thanks in Advance,

Bhuvnesh
  • 1,055
  • 9
  • 29
  • 1
    Something like this https://stackoverflow.com/questions/33291245/rxjava-delay-for-each-item-of-list-emitted ? – user Jan 11 '19 at 15:04
  • What about storing the items in a Deque and use a coroutine that launches a suspending function to get the first element of the deque one a second ? – Ariles Jan 11 '19 at 15:43
  • Your requirement is confusing. If data arrives once a millisecond and can be emitted only once a second, then after one second, you are 999 emissions behind and will never catch up. What do you want to do with them? – Bob Dalgleish Jan 11 '19 at 16:27
  • @BobDalgleish, yes now 999 emissions will emit at every second one by one – Bhuvnesh Jan 11 '19 at 18:49
  • 1
    After 1 day, you will be about 86,313,600 items behind; after 12 days, you will be more than 1 million items behind. Do you not see a problem? – Bob Dalgleish Jan 11 '19 at 19:43
  • @BobDalgleish, Yes but it's not long time process like 12 days. it complete process of 10 to 15 minutes. – Bhuvnesh Jan 14 '19 at 09:43
  • @BobDalgleish , It is something like buffering and streaming items. – Bhuvnesh Jan 14 '19 at 12:15

2 Answers2

1

What about storing the items in a Deque. Then, use a coroutine that launches a suspending function to get the first element of the deque once every second ?

Here is some quick and dirty code just to make sure it works. You can run this code online on the kotlin website. Please keep in mind that I'm very new to Kotlin.

val deque: Deque<String> = ArrayDeque()
var refMillisAdd: Long = 0
var refMillisTake: Long = 0

fun main() {

    println(" Delay(ms) -> Action")
    println("---------------------")

    kotlinx.coroutines.runBlocking {

        launch {

            refMillisAdd = currentTimeMillis()
            refMillisTake = currentTimeMillis()

            for(i in 0..20){
               oncePer10ms(i.toString())
               refMillisAdd = currentTimeMillis()
            }

            for(i in 0..6){
                oncePerSecond()
                refMillisTake = currentTimeMillis()
            }
        }
    }
}

suspend fun oncePerSecond(){
    kotlinx.coroutines.delay(1_000L)
    println("  ${currentTimeMillis() - refMillisTake} -> TAKE ${deque.pop()}")
}

suspend fun oncePer10ms(item: String){
    kotlinx.coroutines.delay(10L)
    deque.add(item)
    println("  ${currentTimeMillis() - refMillisAdd} -> ADD $item")
}

The code above prints:

 Delay(ms) -> Action
---------------------
  17 -> ADD 0
  11 -> ADD 1
  10 -> ADD 2
  10 -> ADD 3
  10 -> ADD 4
  10 -> ADD 5
  10 -> ADD 6
  10 -> ADD 7
  10 -> ADD 8
  11 -> ADD 9
  10 -> ADD 10
  10 -> ADD 11
  10 -> ADD 12
  11 -> ADD 13
  10 -> ADD 14
  10 -> ADD 15
  11 -> ADD 16
  10 -> ADD 17
  10 -> ADD 18
  10 -> ADD 19
  11 -> ADD 20
  1223 -> TAKE 0
  1000 -> TAKE 1
  1000 -> TAKE 2
  1001 -> TAKE 3
  1000 -> TAKE 4
  1000 -> TAKE 5
  1000 -> TAKE 6
Ariles
  • 333
  • 1
  • 14
1

This function extension for Observable class is exactly what you need:

fun <T> Observable<T>.delayBetweenItems(timeout: Long, unit: TimeUnit): Observable<T> =
    Observable.zip(this, Observable.interval(timeout, unit), BiFunction<T, Long, T> { item, _ -> item })

You can declare it in some utility class in your project and then apply it just like other RxJava operators:

publishSubject
    .delayBetweenItems(1000, TimeUnit.MILLISECONDS)
    .subscribeOn(Schedulers.computation())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe {
        // Should execute at every 1 second
    }
jackqack
  • 529
  • 5
  • 6
  • It is working..but sometime(after a long time) it is getting disposed automatically. and no item is getting emit. – Bhuvnesh Jan 14 '19 at 12:12
  • @RajatSharma I think the reason is in how you use it in Android rather than in a function itself. Try to check your code for subscribe and dispose logic. – jackqack Jan 14 '19 at 14:43
  • it may be due we have not handled back press in it. – Bhuvnesh Jan 18 '19 at 20:39