RXKotlin Break Inside doOnNext and Call Another Function - android

i am using rx kotlin newly and didn't understand all of it yet. I am trying to loop over a list of queries, and execute them one by one. in this list i have a special string that once reached, i want to break the loop and perform another function
how can i do this in the below example?
fun runQueries() {
Observable.fromIterable(queriesTemp)
.subscribeOn(Schedulers.computation())
.doOnNext { query ->
if (query.contains("COMPLETION OF SDF QUERIES")) {
if (loginStatus == StaticVariables.FT_CASE_NEW_LOGIN) {
tasksQueriesTemp = arrayOfNulls(queries.size - queries.indexOf(query))
System.arraycopy(queries, queries.indexOf(query), tasksQueriesTemp, 0, tasksQueriesTemp!!.size)
}
// break the loop here
runOtherQueries()
break
}
if (!TextUtils.isEmpty(query)) {
mDatabase.execSQL(query, false, "")
}
action(tasksQueriesTemp!!.indexOf(query))
}
.doOnComplete { executeOtherUpdates(tasksQueriesTemp) }
.observeOn(AndroidSchedulers.mainThread())
.subscribe()
}
fun runOtherQueries() {
}

Factor out the part you want to break on from the doOnNext use takeWhile:
val broken = AtomicBoolean();
Observable.fromIterable(queriesTemp)
.subscribeOn(Schedulers.computation())
.takeWhile { query ->
if (query.contains("COMPLETION OF SDF QUERIES")) {
if (loginStatus == StaticVariables.FT_CASE_NEW_LOGIN) {
tasksQueriesTemp = arrayOfNulls(queries.size -
queries.indexOf(query))
System.arraycopy(queries, queries.indexOf(query),
tasksQueriesTemp, 0, tasksQueriesTemp!!.size)
}
// break the loop here
runOtherQueries()
broken.set(true)
return#takeWhile false // whatever the Kotlin syntax is for local returns
}
return#takeWhile true
}
.doOnNext { query ->
if (!TextUtils.isEmpty(query)) {
mDatabase.execSQL(query, false, "")
}
action(tasksQueriesTemp!!.indexOf(query))
}
.doOnComplete {
// if you don't want to execute the other updates if the code
// in takeWhile has "broken out of the loop"
if (!broken.get())
executeOtherUpdates(tasksQueriesTemp)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe()

Related

RxJava which operator to use

Is there any operator in RxJava to jump to the fetchAllParams(it) function if the filter operator returns false
That is, if UserAvailable.NOT_DETERMINED, I make a delay of 5 seconds and resend the same request, but if UserAvailable.DETERMINED, then the filter statement returns false and nothing happens.
fun checkUserAvailability(): Single<UserAvailable> = repository.serviceAvailable
.flatMap { fetchAllParams(it) }
.filter { it == UserAvailable.NOT_DETERMINED }
.delay(5, TimeUnit.SECONDS)
.flatMapSingle {
checkUserAvailability()
}
I also tried this option. How to put a delay just before the call to checkUserAvailability(), and not before flatMap
fun checkUserAvailability(): Single<UserAvailable> = repository.serviceAvailable
.flatMap { fetchAllParams(it) }
.flatMap {
if (it != UserAvailable.NOT_DETERMINED) {
Single.just(it)
} else {
checkUserAvailability()
}
}

RxJava retryWhen with updated value + concurrency

I'd like to verify two things:
if the way I use retryWhen is correct or not. Basically, when an exception is caught, I want to get an updated value and rerun the sequence.
if another function also needs value, how to make it waits for updateValue to complete in the first instance? I've played with .share() and RxReplayingShare but I'm not sure how to use those properly.
val value = 0
#Test
fun test() {
executeFunction()
.retryWhen { errors -> errors.flatMap { error ->
if (error is WrongValue) {
updateValue()
.doOnSuccess { value = it }
.toObservable()
} else {
Observable.error(error)
}
}
}
}
fun executeFunction(): Single<Int> =
if (value == 0) {
Single.error(WrongValue())
} else {
Single.just(value)
}
fun updateValue(): Single<Int> = Single.just(1)

Wanted to fetch api after getting true value from observable emitter in RxJava

I am working on RxJava. I have created a random boolean stream of true and false values for observable class.
The observable class should be get repeated after a random duration of x seconds (between 10 and 90 seconds). After each true value, I need to call API and update the UI.
I have written the following code to generate random boolean values and pass them through observable. But how to repeat observable after every x seconds?
val r = Random
val apiResultStream = Observable.create(object : Observable.OnSubscribe<Boolean> {
override fun call(subscriber: Subscriber<in Boolean>) {
// emit true or false
subscriber.onNext(r.nextBoolean())
}
}).repeat(10)
apiResultStream
.subscribe { result ->
if (result === true) {
Log.v("ABC",""+result);
callAPI()
} else {
//callFailureApi()
Log.v("ABC",""+result);
}
}
I guess Observable.interval(30, TimeUnit.SECONDS) is what you need:
Observable.interval(30, TimeUnit.SECONDS) //also can specify scheduler
.flatMap { apiResultStream }
.subscribe { result ->
if (result === true) {
Log.v("ABC",""+result);
callAPI()
} else {
//callFailureApi()
Log.v("ABC",""+result);
}
}

How to iterate over a list, and when finish launch a method with RXJava

I have a list of data models, so I have to apply a method that returns a view.
When everything is calculated, I have to launch a method, which makes another type of calculation.
The problem is that as I have it, at each iteration of the second method is launched.(for sure I'm missing something or doing bad, but my knowledge of RX is quite low)
Is it possible to make all the calculations for each method, and when finished, launch this method only once?
val markersViewList = hashMapOf<String, View>()
val subscription = Observable.fromIterable(retrivedUserInfoList)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.map { userInfo ->
val markerLayout = setupUpForMarkerLayout(userInfo)
if (markerLayout != null) {
if (userInfo.userId == owner.uid) { //is owner
markerViewList[OWNER] = markerLayout
} else {
if (!markerViewList.containsKey(userInfo.data1)) {
markerViewList[userInfo.data1] = markerLayout
}
}
}
}
.subscribe {
//THIS IS THE METHOD THAT ONLY HAS TO BE CALCULATED ONCE
createImages(retrivedUserInfoList,markerViewList)
}
addSubscription(subscription)
You can use ignoreElements() operator for it:
val markersViewList = hashMapOf<String, View>()
val subscription = Observable.fromIterable(retrivedUserInfoList)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.map { userInfo ->
val markerLayout = setupUpForMarkerLayout(userInfo)
if (markerLayout != null) {
if (userInfo.userId == owner.uid) { //is owner
markerViewList[OWNER] = markerLayout
} else {
if (!markerViewList.containsKey(userInfo.data1)) {
markerViewList[userInfo.data1] = markerLayout
}
}
}
}
.ignoreElements()
.subscribe {
//THIS IS THE METHOD THAT ONLY HAS TO BE CALCULATED ONCE
createImages(retrivedUserInfoList, markerViewList)
}
addSubscription(subscription)
It will turn your Observable to Completable so your subscribe block will be invoked only once on complete.

RxJava - use variables of a different types (results of a multiple chain operators) within "subscribe" lambda

I'm trying to rewrite following rx-code in such way to remove a subscription within another subscription and to make code look more idiomatic:
private fun foo() {
compositeDisposable.add(getApiDataObservable().subscribe({ result ->
if (!result.isSuccess) {
mutableLiveData.value = "errorMessage"
} else {
compositeDisposable.add(Observable.zip(firstObservable,
secondObservable,
BiFunction<FirstObject, SecondObject, Pair<FirstObject, SecondObject>>
{ obj1, obj2 -> Pair(obj1, obj2) }
).subscribe({
//there I need to use result and pair values
}, {
Timber.e(it)
}))
}
}))
}
I'm tried something like this:
private fun foo2() : Disposable {
return getApiDataObservable()
.filter { result.isSuccess }
.flatMap {
//it - result
Observable.zip(firstObservable,
secondObservable,
BiFunction<FirstObject, SecondObject, Pair<FirstObject, SecondObject>>
{ obj1, obj2 -> Pair(obj1, obj2) })
}.subscribe {
//it - Pair<FirstObject, SecondObject>
// here I need both - result and pair values
},{ mutableLiveData.value = "errorMessage"}
}
But I have a misunderstanding in a next point : how can I obtain both - result value from the getApiDataObservable() and a pair from the Observable.zip(..) call within subscribe.
First thought that comes to the mind : to store result value in some variable and use it inside subscribe lambda. but maybe it is possible to achieve in more elegant and more-rx way.
You can create wrapper around result like that
class CompoundResult(apiResult: Result, firstObject: FirstObject, secondObject: SecondObject)
and modify foo2() function
private fun foo2() : Disposable {
return getApiDataObservable()
.flatMap {
if(!it.isSuccess) {
Observable.error(Throwable("errorMessage"))
} else {
Observable.zip(firstObservable,
secondObservable,
BiFunction<FirstObject, SecondObject, CompoundResult>
{ obj1, obj2 -> CompoundResult(it, obj1, obj2) })
}
}.subscribe ({
//it - CompoundResult
// here I need both - result and pair values
},{ mutableLiveData.value = it.localizedMessage })
}
Here i throw error, if result of api request is not success. That allow to trigger onError() of your subscriber
I think that you can combine both result and pair when both are accessible an return a combined object. In the example below it is a Pair<Result, Pair<FirstObject, SecondObject>>, but maybe it is better to create a dedicated object.
private fun foo2() : Disposable {
return getApiDataObservable()
.filter { result.isSuccess }
.flatMap {
//it - result
Observable.zip(firstObservable,
secondObservable,
BiFunction<FirstObject, SecondObject, Pair<FirstObject, SecondObject>>
{ obj1, obj2 ->
val pair = Pair(obj1, obj2)
Pair(it, pair)
})
}.subscribe {
//it - Pair<Result, Pair<FirstObject, SecondObject>>
},{ mutableLiveData.value = "errorMessage"}
}
Also note that the .filter { result.isSuccess } will not trigger further chain if the result.isSuccess = false and you will not receive any callback.

Categories

Resources