I would like to build a Repository
class that returns a Single<Something>
.
The class should first look in a Cache
which returns Maybe<Something>
and if the Maybe
completes go off to my Service
that returns Single<Something>
interface Cache {
fun getSomething(): Maybe<Something>
}
interface Service {
fun getSomething(): Single<Something>
}
class Repository (
private val cache: Cache,
private val service: Service
) {
fun getSomething(): Single<Something> {
return cache.getSomething()
.????(feed.getSomething()) //onCompleteTransformToSingle() or similar
}
}
I have searched through the JavaDoc but it does not seem that a transformer for this scenario exists.
Is there a nice way of handling this?
Unfortunately, there is no straightforward way to convert an Observable to Maybe (unless you are interested in just the firstElement ). You can convert it to Single first though and then to Maybe using toMaybe . This observable is only concerned about two things, if some action is executed or an error is encountered.
Single and Completable are new types introduced exclusively at RxJava that represent reduced types of Observable , that have more concise API. Single represent Observable that emit single value or error. You can think of the differences like the differences of a method that returns: Collection of Objects - Observable.
Single is an Observable which only emits one item or throws an error. Single emits only one value and applying some of the operator makes no sense. Like we don't want to take value and collect it to a list.
Here are two fairly simple options you could use. The first I find more explicit. The second has the benefit that you will call the network on any error in the cache.
These assume a Maybe is returned from the cache. For example if no value is found in the cache, return Maybe.empty()
1) If there is an empty in the stream, switchIfEmpty() will use the alternate observable which calls the network. If no empty is in the stream, the network will never be called.
override fun getSomething(): Single<Something> {
return cache.getSomething()
.switchIfEmpty(
Maybe.defer {
feed.getSomething().toMaybe()
}
)
.toSingle()
}
2) An empty maybe will return an error when cast toSingle(), triggering the network call.
override fun getSomething(): Single<Something> {
return cache.getSomething()
.toSingle()
.onErrorResumeNext {
feed.getSomething()
}
}
When you need to perform RxJava operations using metadata (absence of cached result), you may have to transform your observer chain into a metadata stream, using materialize()
.
(Apologies for my lack of fluency in Kotlin)
fun getSomething(): Single<Something> {
return cache.getSomething()
.toObservable()
.materialize()
.take(1)
.flatMap( it.hasValue() ? Single.just( it.getValue() )
: Single.fromCallable( apiCall() )
);
}
The materialize()
operator turns the observer stream into a stream of Notification
s. You can then inspect the first notification, and if it has a value, use that. Otherwise, make your network call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With