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()
}
}
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)
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);
}
}
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.
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.