Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - wait for multiple LiveData to be observe before running function

I am using a viewModel to pull livedata from a room data base. I have 2 LiveData that I pull from my viewModel and then I will run a function to pull data from my server. I need both values to be set before running my function that will get info from my server because these values are part of the body of the post.

This is part of my activity

var locationSeleted:Long=0L

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView<ActivityBinding>(this,R.layout.activity)

        //This is to get the viewmodel
        val application = requireNotNull(this).application
        val dataSource = Database.getInstance(application).DatabaseDao
        val viewModelFactory = ViewModelFactory(dataSource, application)
        val ViewModel = ViewModelProviders.of(this,viewModelFactory).get(ViewModel::class.java)

        binding.ViewModel = ViewModel
        binding.setLifecycleOwner (this)

        //Get location from livedata
        ViewModel.Location.observe(this, Observer {location ->

            if (location == null){
                //do something
            }
            else{
                locationSeleted = location.locationId
            }

        })

        //listens to the live data of the products value
        ViewModel.Products.observe(this, Observer{products ->
            
            if (products == null){
                //do something
            }
            else{
                myfunction(products)
            }

        })

This is part of my viewmodel

class ViewModel(val database: DatabaseDao, application: Application) : AndroidViewModel(application) {


    //This gets the location selected
    var Location: LiveData<LocationSelect> = database.get_location()

    //This line gets the products
    var Products: LiveData<Array<Products>> = database.get_products()


My current code works but I can imagen that if Location LiveData is delayed then myfunction will run with no location and the Post call will false. My question is how can I call myfunction when both location and products set from the viewModel? or is there a better way of doing this.

Thanks you

like image 535
Max Avatar asked Aug 21 '20 19:08

Max


People also ask

Can LiveData have multiple observers?

How many times can I observe? In theory, we can observe livedata with multiple observers, just like the good old pub-sub pattern, right? Well, let's test this out. Let's create a super simple livedata.

Is LiveData asynchronous?

Use LiveData with RoomThe generated code runs the query asynchronously on a background thread when needed. This pattern is useful for keeping the data displayed in a UI in sync with the data stored in a database.

Why use flow instead of LiveData?

StateFlow and LiveData have similarities. Both are observable data holder classes, and both follow a similar pattern when used in your app architecture. The StateFlow and LiveData do behave differently: StateFlow requires an initial state to be passed into the constructor, while LiveData does not.


Video Answer


1 Answers

You can use a MediatorLiveData so you only have to observe one thing, and it fires only when both items are received, and on every change after that.

In the ViewModel:

val locationAndProductsLiveData: LiveData<Pair<LocationSelect, Array<Products>>> = 
    object: MediatorLiveData<Pair<LocationSelect, Array<Products>>>() {
        var location: LocationSelect? = null
        var products: Array<Products>? = null
        init {
            addSource(Location) { location ->
                this.location = location 
                products?.let { value = location to it }
            }
            addSource(Products) { products ->
                this.products = products 
                location?.let { value = it to products }
            }
        }
    }

In your Activity:

ViewModel.locationAndProductsLiveData.observe(this) { (location, products) ->
    locationSelected = location.Id
    myFunction(products)
}
like image 117
Tenfour04 Avatar answered Oct 20 '22 19:10

Tenfour04