Observable.just() which returns Unit in Kotlin - android

I have a piece of Observable which in the end either returns an error and retries or just returns onNext. I don't need anything in onNext, so this is just an Observable<Unit>.
Now the problem is that at the end of the chain I have to hit this onNext and I don't have anything other than good old Observable.just(). But I cannot return Observable.just(null) because it returns Nothing?, not Unit. I cannot return Unit, because it's not instantiable. Therefore I have Observable.just(null).map{}. It works, but looks ugly. Any idea for a better solution?

Use Observable.just(Unit). Unit itself is the single object of the type Unit.

Related

How can I use data from another flow data in flow? (Kotlin Flow)

I wrote the code as below.
suspend fun getDataByRegion(): Flow<Result?> {
// getRegion() return Flow<Region>
return getRegion().map { region: Region ->
repository.requestDataFromServer(region)
}
}
The problem is that repository.requestDataFromServer(region) called twice.
So I think I should use operators like zip or combine.
When using these operators, how can the second flow use the data of the first flow?
With combine and zip operators you can not depend on the other's result. So in general your chaining approach with map is OK.
There is several options you have:
Assuming your repository method is not called from anywhere else, the reason for it being called twice is that the region Flow is emitting twice. So try to find out why this is the case.
Anyhow if your region Flow method returns the same region twice you can fix it by simply adding
.distinctUntilChanged() after getRegion() like:
getRegion().distinctUntilChanged().map { region: Region ->
repository.requestDataFromServer(region)
}
It will make sure your region Flow doesn't emit redundantly with the same data. Alternatively add distinctUntilChanged() directly to the repository method, if this is always the expected behavior.
Ask yourself if this method really needs to return a stream (Flow). I guess you need a stream since the region can change at runtime and you want something in your app to update automatically? But if not you could simply convert the stream to a single result:
val region = getRegion().first()
repository.requestDataFromServer(region)

How to unit test RxJava Completable.error on Android

I have a function that returns a Completable which returns Completable.error(RuntimeException("message")) if another function fails or Completable.complete() if not.
I was trying to write a unit test for this and see that the flow is going correctly to the error and success code but in my test I cannot differentiate between them using
underTest.unregisterFromService().test().assertComplete().assertNoErrors()
Does anyone know how the Completable.error() value can be checked in unit test?
I believe what you're looking for is
yourCompletable
.test()
.assertErrorMessage("your error message")
There is an assertError for that, most cases use the version that takes the Thorwable's type as a parameter, from the docs:
Asserts that this TestObserver/TestSubscriber received exactly one onError event which is an instance of the specified errorClass class.
Usage:
yourCompletable
.test()
.assertError(RuntimeException::class.java)
Here you can find the three versions of assertError.

Zipping a Maybe and Single leads to no result being emitted

I'm making an Android application. I've to zip results from two places: One from SharedPreferences as a Maybe and other from the Room Persistence library(basically SQLite) as a Flowable.
I'm using the following code:
repository.getMaybe()
.subscribeOn(Schedulers.io)
.toSingle()
.zipWith(repository.getFlowable().single(DEFAULT VALUE), BiFunction { t1: DataType1, t2: DataType2 -> Pair(t1, t2) }
.subscribe()
repository.getMaybe() is the Maybe source mentioned in the first paragraph. Likewise, repository.getFlowable() is the Flowable source.
I've tried using doOnEvent(to Log statements) on the Maybe source, the Flowable source and the zipped source. Only the Maybe source emits successfully. Others don't do anything at all.
The Flowable source is used in various other parts of my application and it is not at all an issue.
What am I doing wrong?
If your Maybe does not return a value then calling toSingle would result in an Single.error. This would mean it would reach the zipWith as an arrow and it would never bother evaluating the value, since there is no value to zip with.
Thanks to Akarnokd, I tried removing the single(DEFAULT ITEM) part. It worked. On looking up the documentation at http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html, I came across this:
single(T defaultItem)
Returns a Single that emits the single item
emitted by the source Publisher, if that Publisher emits only a single
item, or a default item if the source Publisher emits no items.
Basically, the Flowable should emit only once. So, I'm using firstOrError() in it's place.

flatMap() in kotlin

If i make a Single invocation using Retrofit as example in Kotlin, i want to check the resulted answer and keep going with a Single or an error. As example
model.doRequest()
.flatMap { t: Response ->
if(!h.hasError) {
return#flatMap model.doAnotherRequest()
} else {
return#flatmap Single.error<Throwable>(Throwable("error))
}
}
If i make another flatMap(), subscribe() or any other things, RxJava won't know that I want to continue with response given by the doAnowhtRequest(), instead will return Any!. How i can get data given by second request?
In Java, Single.error isn't interpreted so RxJava will continue to give me the response in next invocations.
Assuming you want to return the same thing as doAnotherRequest() the problem is with Single.error<Throwable>(Throwable("error)). You're hitting the compiler that you're returning a Single<Throwable>, but you want to return a Single<whatever doAnotherRequest returns>.
Say your doAnotherRequest returns Single<Foo>, then you'd want to return Single.error<Foo>(Throwable("error)), which will return a single that will emit an error with the given exception.
Kotlin tries to infer the type you want to return, but because you're returning 2 types that the "most common" type is Any, kotlin can only infer it's that you want to return.

OnSubscribe position causes OnComplete event to fire prematurely

I'm feeling a bit curious about how .subscribeOn() actually works on RxJava.
I have this piece of code that works as intended:
return endpoints.getRecentConversations(page)
.map().flatMap().doOnNext() //etc etc...
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
I was reading this article, trying to understand what the difference between subscribeOn and observeOn when this line caught my eye:
Position does not matter
subscribeOn can be put in any place in the stream because it affects
only the time of subscription
Which sounds perfectly fine. But I was feeling a bit skeptical I decided to test it. So I changed the code above (switched lines 2 and 3):
return endpoints.getRecentConversations(page)
.subscribeOn(Schedulers.io())
.map().flatMap().doOnNext() //etc etc...
.observeOn(AndroidSchedulers.mainThread())
As a result, I get an premature onComplete() on my subscriber. onNext() is never called and no errors are present in my logcat.
I can leave things the way they were, but I'd like to know why this is happening. Is it true that position doesn't matter? Is it something wrong with my code? Here's how my code looks
Yes, the position does matter a lot in RxJava, It's called upstream & downstream.
It's because you are subscribing to a hot observable
Watch this video to understand it better: Common RxJava Mistakes
https://www.youtube.com/watch?v=QdmkXL7XikQ&t=768s
There are two types of observables: Hot & cold.
A “hot” Observable may begin emitting items as soon as it is created,
and so any observer who later subscribes to that Observable may start
observing the sequence somewhere in the middle. A “cold” Observable,
on the other hand waits until an observer subscribes to it before it
begins to emit items, and so such an observer is guaranteed to see the
whole sequence from the beginning.

Categories

Resources