根据另一个 Spinner 选择 (LiveData) 过滤 Spinner 的 Observed ViewModel 数据

Posted

技术标签:

【中文标题】根据另一个 Spinner 选择 (LiveData) 过滤 Spinner 的 Observed ViewModel 数据【英文标题】:Filter Observed ViewModel data for Spinner based on another Spinners selection (LiveData) 【发布时间】:2021-11-21 17:35:32 【问题描述】:

我有两个 Spinner,每个都由 ArrayList 填充,在 Fragment 的 ViewModel 中观察到如下:

InventoryAddEdit 片段

        // Observe ProductGroups and populate Spinner
        businessViewModel.allAppDataProductGroups.observe(viewLifecycleOwner,  productGroupArrayList -> // ArrayList<ProductGroupObject>
            if (!productGroupArrayList.isNullOrEmpty())
                val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, productGroupArrayList)
                binding.inventoryAddEditProductGroupSpinner.adapter = adapter
            
        )

// Observe ProductTypes and populate Spinner
        businessViewModel.allAppDataProductTypes.observe(viewLifecycleOwner,  productTypeArrayList -> // ArrayList<ProductTypeObject>
            if (!productTypeArrayList.isNullOrEmpty())
                val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, productTypeArrayList)
                binding.inventoryAddEditProductTypeSpinner.adapter = adapter
                binding.inventoryAddEditProductTypeSpinner.setSelection(17) // Sets default value
            
        )

我试图避免将数据保留在 Fragment (MVVM) 中,所以我想知道如何根据第一个 ArrayList 的选择最好地过滤第二个 ArrayList。

我想我可以在第一个微调器上使用onItemSelected 方法来取消观察者并重新附加,然后通过选择第一个微调器来过滤新观察到的 ArrayList。但是,这似乎有点笨拙。另一个想法是在 ViewModel 中创建另一个过滤列表,但这意味着 ViewModel 中有更多数据。

请问还有其他选择吗?

有关信息,ProductGroupObject 和 ProductTypeObject 如下所示:

ProductGroupObject

@IgnoreExtraProperties
data class ProductGroupObject (

    //ProductGroup fields (1 fields)
    var productGroup: String = "",

    @ServerTimestamp
    var dateEditedTimestamp: Date? = null,

    @Exclude @set:Exclude @get:Exclude
    var productGroupID: String = ""

) : Serializable 

    override fun toString(): String 
        return productGroup
    

ProductTypeObject

@IgnoreExtraProperties
data class ProductTypeObject (

    //ProductType fields (2 fields)
    var productType: String = "",
    var productGroup: String = "",

    @ServerTimestamp
    var dateEditedTimestamp: Date? = null,

    @Exclude @set:Exclude @get:Exclude
    var productTypeID: String = ""

) : Serializable 

    override fun toString(): String 
        return productType
    

    fun detailsText(): String 
        val detailsString = StringBuilder()

        if(productTypeID.isNotEmpty()) detailsString.append("$productTypeID\n")
        if(productType.isNotEmpty()) detailsString.append("$productType\n")
        if(productGroup.isNotEmpty()) detailsString.append("$productGroup\n")

        return detailsString.toString()
    

【问题讨论】:

【参考方案1】:

所以我想出的最佳解决方案是为 ViewModel 中的每个 Spinner 数据集创建一个“完整列表”和“过滤列表”+每个 Spinner 的“当前选择”对象(也保存在 ViewModel 中)。

“完整列表”由云数据库在启动时填充,“过滤列表”通过以下代码根据 Spinner 选择进行过滤:

        binding.inventoryAddEditProductGroupSpinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener

            override fun onItemSelected(parent:AdapterView<*>?, view: View?, position: Int, id: Long)

                val productGroupObject = parent?.selectedItem as ProductGroupObject
                if (productGroupObject.productGroupID.isNotEmpty())
                    businessViewModel.updateCurrentProductGroupVMLiveData(productGroupObject.productGroupID)
                
            

这会更新“过滤列表”(过滤“完整列表”),该列表将数据保存到任何链接的 Spinner,如下所示:

    fun updateCurrentProductGroupVMLiveData (currentProductGroupId: String) 
        val newProductGroup = allAppDataProductGroups.value?.find  productGroup -> productGroup.productGroupID == currentProductGroupId 
        _currentProductGroup.value = newProductGroup
        if(newProductGroup?.productGroup != null) 
            val filteredProductsList = allAppDataProductTypes.value?.filter  productTypeObject -> productTypeObject.productGroup == newProductGroup.productGroup as ArrayList<ProductTypeObject>
            _filteredAppDataProductTypes.value = filteredProductsList
        

        // UPDATE OTHER SPINNERS HERE
        
        Log.d(TAG, "updateCurrentProductGroupVMLiveData(): '_currentProductGroupId.value' updated ($currentProductGroupId)")
    

我遇到的一个问题是由于 LiveData 的工作方式,视图可以为空,这在以下帖子中得到了解决:Spinner Listener LiveData Issue

【讨论】:

以上是关于根据另一个 Spinner 选择 (LiveData) 过滤 Spinner 的 Observed ViewModel 数据的主要内容,如果未能解决你的问题,请参考以下文章

Spinner 和 Button 无法转到另一个视图

选择项目后更改 Spinner 列表内容 Android

如何通过多项选择重新调整 Spinner 中项目的高度?

有没有办法让微调器选项打开另一个微调器?

在 Robotium 中选择 Spinner 错误项

UI组件之AdapterView及其子类Spinner控件具体解释