【问题标题】:Kotlin - wait for multiple LiveData to be observe before running functionKotlin - 在运行函数之前等待多个 LiveData 被观察
【发布时间】:2020-08-21 19:05:59
【问题描述】:

我正在使用 viewModel 从房间数据库中提取实时数据。我从我的 viewModel 中提取了 2 个 LiveData,然后我将运行一个函数从我的服务器中提取数据。在运行将从我的服务器获取信息的函数之前,我需要设置这两个值,因为这些值是帖子正文的一部分。

这是我的活动的一部分

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)
            }

        })

这是我的视图模型的一部分

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()


我当前的代码有效,但我可以想象,如果 Location LiveData 延迟,那么 myfunction 将在没有位置的情况下运行,并且 Post 调用将为 false。我的问题是当从 viewModel 设置位置和产品时如何调用 myfunction?或者有更好的方法吗?

谢谢你

【问题讨论】:

    标签: android kotlin viewmodel android-livedata


    【解决方案1】:

    您可以使用 MediatorLiveData,因此您只需要观察一件事,并且仅在收到这两个项目时以及之后的每次更改时才会触发。

    在 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 }
                }
            }
        }
    

    在您的活动中:

    ViewModel.locationAndProductsLiveData.observe(this) { (location, products) ->
        locationSelected = location.Id
        myFunction(products)
    }
    

    【讨论】:

    • addSource() 不起作用。有我需要添加的库吗?
    • 糟糕,您必须指定类的类型。不知道为什么它没有被推断出来。见编辑。
    • 谢谢你的工作!我的一个问题是以下代码在做什么? products?.let { value = location to it } And location?.let { value = it to products } 我知道我们正在为 livedata 设置本地值。但我不明白语法。你能解释一下吗?
    • ?.let 表示仅当接收者不为空时才运行 let lambda。因此,value 仅在已知两个源都具有非空数据时才会更新。两个项目之间的to 是一个中缀函数,用于创建其中的一个Pair
    【解决方案2】:

    您可以使用实时数据进行观察。在您的视图模型中:

    val _weHaveAllTheData = MutableLiveData(pairToShowSpinner)
    val weHaveAllTheData: LiveData<Pair<Boolean, Boolean>> = _weHaveAllTheData
    
    fun updateTheData(int firstOrSecond: Int) { 
        val pair = _weHaveAllTheData.value
        if (firstOrSecond = 1) {
           
           val secondPair = pair?.second as Boolean
           val pairInObservable = Pair(true, secondPair)
           _weHaveAllTheData.value = pairInObservable
        } else {
           val firstPair = pair?.first as Boolean
           val pairInObservable = Pair(firstPair, true)
           _weHaveAllTheData.value = pairInObservable 
        }
    
    }
    

    在你的活动中:

        //Get location from livedata
        ViewModel.Location.observe(this, Observer {location ->
    
            if (location == null){
                //do something
            }
            else{
                locationSeleted = location.locationId
            }
            ViewModel.updateTheData(1)
    
    
        })
    
    //listens to the live data of the products value
        ViewModel.Products.observe(this, Observer{products ->
            
            if (products == null){
                //do something
            }
            else{
                ViewModel.updateTheData(2)
                
            }
    
        })
    
        ViewModel.weHaveAllTheData.observe(lifecycleOwner, Observer {
            val positivePair = Pair(first = true, second = true)
            if (it == positivePair)
                myfunction(ViewModel.Products)
        })
    

    【讨论】:

    • 要启动 MutableLiveData,请使用值对 ToShowSpinner。初始化 MutableLiveData 需要什么?
    • _weHaveAllTheData = MutableLiveData(Pair(true, true))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多