FutureShocked
FutureShocked

Reputation: 888

Using LiveData without LifecycleObserver

I'm writing an app which is (attempting) to adhere to the MVVM design pattern. I'd like to observe changes to the model layer from other parts of that layer. For example

Let's say I'm exposing a list of objects from my database using room:

@Dao
interface MyDao {
    @Query("SELECT * FROM myTable")
    fun getAllElements(): LiveData<List<Element>>
}

I'd like to be able to observe changes like I normally would using a lifecycle owner using LiveData.observeForever(). Something like:

class BusinessLogicPartOfTheModel(private val myDao: MyDao) {
    private var allElements = listOf<Element>()

    init {
        myDao.getAllElements().observeForever { observedElements ->
            allElements = observedElements
        }
}

However, I'm finding that if I register an observer like that as well as a more standard observer in a ViewModel and Fragment like this:

class MyViewModel(private val myDao: MyDao) : ViewModel() {
    fun getAllElements(): LiveData<List<Elements>> {
        myDao.getAllElements()
    }
}

class MyFragment : Fragment() {
    private val myDao /* initialized here */
    private val myViewModel /* initialized here */
    private val logic = BusinessLogicPartOfTheModel(myDao)

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val obs = Observer<List<Element>> {
             // do a thing
        }
        myViewModel.getAllElements.observe(viewLifeCycleOwner, obs)
    }
}

Only the observer in the fragment is called, and not the observer in the business logic object. I can successfully observe updates in the fragment and pass the events back down to the business logic, but that seems like an incredibly unnecessary level of indirection. Am I missing a step here or is this just unlikely to function the way I want it to?

Upvotes: 1

Views: 2086

Answers (1)

Archie G. Qui&#241;ones
Archie G. Qui&#241;ones

Reputation: 13648

You probably should be using MediatorLiveData instead.

MediatorLiveData accepts another LiveData as source of events by adding it to the MediatorLiveData.

You could use something like,

val mediatorLiveData = MediatorLiveData<Item>().apply {
    addSource(yourLiveData) {
        // do something here
    }
}

You could also look at Transformations.

Transformations has methods such as Transformation.map() and Transformation.switchMap() which simply uses MediatorLiveData under the hood.

Upvotes: 2

Related Questions