DEV Community

Tony Robalik
Tony Robalik

Posted on

A Custom LiveData that has onActive and onInactive Listeners -- Tested

I was expecting my next post to continue my series on dagger.android, but today's adventures were too strange not to relate to others.

Need: a LiveData object that would "do something" when it had an active observer.

Observation: LiveData has two hooks: onActive() and onInactive() that are designed for just this purpose.

Plan: Extend MutableLiveData with a class named ActiveMutableLiveData that does something with these hooks.

Further observation: if I'm going to push this to production, I should test it to prove to myself I understand what's going on and that my new class behaves as expected.

ActiveMutableLiveData

/** * A form of [MutableLiveData][android.arch.lifecycle.MutableLiveData] that * provides hooks for for [onActive][android.arch.lifecycle.MutableLiveData.onActive] and * [onInactive][android.arch.lifecycle.MutableLiveData.onInactive]. Use these to be * notified when this [LiveData][android.arch.lifecycle.LiveData] gains and loses an * active observer. */ class ActiveMutableLiveData<T>( private val onActiveListener: OnActiveListener ) : MutableLiveData<T>() { constructor(onActive: () -> Unit = {}, onInactive: () -> Unit = {}) : this( onActiveListenerFromLambdas(onActive, onInactive) ) override fun onActive() { onActiveListener.onActive() } override fun onInactive() { onActiveListener.onInactive() } } fun onActiveListenerFromLambdas( onActive: () -> Unit, onInactive: () -> Unit ): OnActiveListener { return object : OnActiveListener { override fun onActive() { onActive.invoke() } override fun onInactive() { onInactive.invoke() } } } interface OnActiveListener { fun onActive() fun onInactive() } 
Enter fullscreen mode Exit fullscreen mode

ActiveMutableLiveDataTest

// Using JUnit5 internal class ActiveMutableLiveDataTest { private val counter = AtomicInteger() private val liveData = ActiveMutableLiveData<Boolean>(onActive = { counter.incrementAndGet() }) @Test fun whenObjectBecomesActive_thenOnActiveListenerIsTriggered() { // Given val lifecycle = TestLifecycle() liveData.observe(lifecycle, Observer { println("$it") }) // verify initial condition assertEquals(0, counter.get()) // When lifecycle.state = Lifecycle.State.STARTED // Then assertEquals(1, counter.get()) } @Test fun expectOnActiveListenerTriggeredEveryTime() { // Given val lifecycle = TestLifecycle() liveData.observe(lifecycle, Observer { println("$it") }) // verify initial condition assertEquals(0, counter.get()) // When lifecycle.state = Lifecycle.State.STARTED lifecycle.state = Lifecycle.State.CREATED lifecycle.state = Lifecycle.State.STARTED // Then assertEquals(2, counter.get()) } class TestLifecycle : LifecycleOwner { var state: Lifecycle.State = Lifecycle.State.INITIALIZED set(value) { registry.markState(value) } private val lifecycle = object : Lifecycle() { override fun addObserver(observer: LifecycleObserver) { // don't care } override fun removeObserver(observer: LifecycleObserver) { // don't care } override fun getCurrentState(): State = state } private val registry = LifecycleRegistry({ lifecycle }) override fun getLifecycle() = registry } } 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)