Application is used to demonstrate how we can easily setup components without explicitly overriding methods like onStart()/onResume()/onPause()/onStop()/onDestroy(). That approach allows to write all configuration code in one place and reduce amount of intermediate variables.
viewLifecycleOwner.configure {
bindState(liveData, txtView) { txtView, state ->
// TODO
}
bindClicks(
view = root,
clickListener = {
// TODO
}
)
bindObservable(
observable = Observable.interval(1, TimeUnit.SECONDS),
action = { source ->
source
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ TODO() }, Throwable::printStackTrace)
},
bindOnEvent = Lifecycle.Event.ON_START
)
}
Using ability to observe lifecycle changes of base android components (Activity, Fragment, etc.), we create Configurator and tie it to component's lifecycle.
Configurator is immutable object and should be created using Builder. In Builder we can add operation (lambda (LifecycleOwner) -> Unit
) and associate it with lifecycle's event, like:
Configurator.Builder()
.addOperation(Lifecycle.Event.ON_RESUME) { TODO() }
To perform action that later (at some Lifecycle.Event) should be reverted, we can use convenient extension function on Builder like this one:
fun <T, R: Any?> Configurator.Builder.bind(
target: T,
crossinline bindAction: (LifecycleOwner, T) -> R,
bindOnEvent: Lifecycle.Event,
crossinline unbindAction: (LifecycleOwner, T, R) -> Unit,
unbindOnEvent: Lifecycle.Event = bindOnEvent.oppositeEvent()
) {
var result: R? = null
addOperation(bindOnEvent) { result = bindAction(it, target) }
addOperation(unbindOnEvent) { unbindAction(it, target, result!!) }
}
and more concrete example for observable:
fun <T> Configurator.Builder.bindObservable(
observable: Observable<T>,
action: (Observable<T>) -> Disposable,
bindOnEvent: Lifecycle.Event = Lifecycle.Event.ON_CREATE,
unbindOnEvent: Lifecycle.Event = bindOnEvent.oppositeEvent()
) {
bind(
target = observable to action,
bindAction = { _, (stream, act) ->
act(stream)
},
bindOnEvent = bindOnEvent,
unbindAction = { _, _, subscription ->
subscription.dispose()
},
unbindOnEvent
)
}
- Activity#onCreate()
- Fragment#onCreate()
- Fragment#onCreateView()
- Configuration is placed in one place. (Not splitted between separate hook methods like onCreate()/onStart()/onResume()/onPause()/onStop()/onDestroy()).
- There is no need in intermediate variables like views, bindings, disposables, etc.
- Need to be configured statically. No ability to add operation at any time of lifecycle.
- Need to be configured at create phase of component.