This is a a kotlin library that helps bridge the gap between iOS RXSwift and RXKotlin/RXJava. There are two useful artifacts that are built together: retrofit-rx
and rx-helpers
.
allProjects {
repositories {
// required to find the project's artifacts
maven { url "https://www.jitpack.io" }
}
}
In your project-level build.gradle:
def latest = // 10 digit hash of commit you wish, or version in the "releases" tab.
dependencies {
// rx helpers
implementation "com.github.fuzz-productions:rx-helpers:${latest}"
// retrofit helpers
implementation "com.github.fuzz-productions:retrofit-rx:${latest}"
}
-
T.asObservable()
=> converts an object of typeT
intoObservable<T>.just
-
T.asMaybe()
=> converts an object of typeT
intoMaybe<T>.just
-
T.asFlowable()
=> converts an object of typeT
intoFlowable<T>.just
-
T.asSingle()
=> converts an object of typeT
intoSingle<T>.just
-
P.asFlowable()
=> converts aPublisher<T>
into aFlowable<T>
-
P.asObservable()
=> converts aPublisher<T>
into aObservable<T>
On top of just pure extension helpers, this library adds a few concepts to RXKotlin:
-
Bind
: analogous tosubscribeBy()
with all methods mapped. -
DisposeBag
:CompositeDisposable
-
Driver
: RXSwift Driver. -
Optional<T>
: Own optionaldata class
with corresponding helper extension operators.
RXJava has concept of subscribe()
and subscribeBy()
(RXKotlin). While these are great,
there is no syntactic equivalent.
This library includes the bind()
operator to map the subscription of an object to the corresponding interfaces:
-
Observer
-
Consumer
-
Emitter
We support Maybe
, Single
, Observable
, and Flowable
. These are duplicative in some places because RXJava does not consolidate the objects with similar hierachy trees, thus we cannot simplify implementation.
Use:
val subject: Subject<User> = PublishSubject.create()
user.asObservable()
.bindTo(subject)
.disposedBy(disposeBag);
Bind on error in debug builds throw an OnErrorNotImplementedException
, while on release builds
we log to Timber
.
We have a convenience operator bindToMain()
which binds various objects onto the main thread. analogous to observeOn(AndroidSchedulers.mainThread()).bindTo()
typealias
to CompositeDisposable
Add a Disposable.disposedBy(disposeBag)
chaining method. It is analogous to RXKotlin addTo()
method.
-
It never fails
-
It delivers events on the
AndroidSchedulers.mainThread()
-
It replays the last event when subscribed to.
-
It can have multiple subscribers.
-
drive()
must happen on the main thread, and will return results on the main thread.
Example:
val userName: Subject<String> = PublishSubject.create()
val userNameRelay: Relay<String> = PublishRelay.create()
userName.asDriver(onErrorJustReturn = "")
.drive(userNameRelay)
.disposedBy(disposeBag)
Instead of using the Javas 8 Optional
, we created our own data class
for this purpose to support older android SDK versions.
Since RXJava disallows null
completely, we needed a way to represent nothing without onError()
terminations from null values.
val op = optionalOf(user)
op.asObservable()
.filterValue() // only emit if value exists
.bindTo(userSubject)
We have a few RX helpers on the Retrofit front.
LoadStatus
=> loading stateretrofit.Result
extensions.
A sealed class
object that represents loading states.
-
None
: Initial stateobject
. Has not loaded yet. -
Loading
: loading stateobject
. -
Error
: contains an errorThrowable
which describes the network error or some other kind. -
Success
: represents successful load. This should contain a<T>
with a value on completion.
Along these lines we have a few convenience operators to make code more expressive and readable:
val loadStatus: Subject<LoadStatus> = BehaviorSubject.create()
networkService.loadData()
.startLoading(loadStatus) // trigger loading
.bindToLoadStatus(loadStatus) { dataSubject.onNext(it) } // on complete, on error, and on success mapped. optional parameters for calllbacks.
.disposedBy(disposeBag)
loadStatus
.filterErrors() // only listen for errors. Return `Observable<LoadStatus.Error>`
loadStatus
.filterSuccess() // listen for success. Return `Observable<Unit>`
loadStatus
.mapToLoadingState() // convenience for map { it == LoadStatus.Loading }
By having a Retrofit Interface return Single<Result<T>>
, you get status of request back in an rx-y way. We added a few operators to make handling them more expressive.
networkService.loadData() // Single<Result<T>>
.filterSuccess() // Maybe<T>
networkService.loadData()
.filterFailures() // Maybe<Throwable>
Also we support Observable
methods for calls listed above.
networkService.loadData()
.doOnSuccess { // do something here }
.doOnFailure { // do something on error }