Spinner 侦听器 LiveData 问题

Posted

技术标签:

【中文标题】Spinner 侦听器 LiveData 问题【英文标题】:Spinner Listener LiveData Issue 【发布时间】:2021-11-27 01:52:37 【问题描述】:

在我的 Fragment 中,我有两个 Spinner。

两者都由在 ViewModel 中观察到的 LiveData 填充,如下所示:

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


// Observe Filtered ProductTypes and populate Spinner
        businessViewModel.filteredAppDataProductTypes.observe(viewLifecycleOwner,  productTypeArrayList ->
            if (productTypeArrayList != null)
                val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, productTypeArrayList)
                binding.inventoryAddEditProductTypeSpinner.adapter = adapter
            
        )

这很好用,但我试图通过设置侦听器并更新 ViewModel 数据,根据当前选择的第一个 Spinner 过滤第二个 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)
                
            

            override fun onNothingSelected(parent: AdapterView<*>)
            
        

这会更新 ViewModel 中的过滤列表,如下所示:

    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
        
        Log.d(TAG, "updateCurrentProductGroupVMLiveData(): '_currentProductGroupId.value' updated ($currentProductGroupId)")
    

但是,如果我将显示的代码添加到 onItemSelected 中,应用程序会崩溃并且我会看到以下错误:

    --------- beginning of crash
2021-10-06 23:06:34.740 17510-17510/com.xxxxx.acorn E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.locators.acorn, PID: 17510
    java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter view
        at com.xxxxx.acorn.business.inventory.InventoryAddEditFragment$setSpinnerListeners$2.onItemSelected(InventoryAddEditFragment.kt)
        at android.widget.AdapterView.fireOnSelected(AdapterView.java:931)
        at android.widget.AdapterView.dispatchOnItemSelected(AdapterView.java:920)
        at android.widget.AdapterView.-wrap1(AdapterView.java)
        at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:890)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

我看到 ViewModel 列表正在发生变化,所以我不知道为什么会导致 NullPointerException。

【问题讨论】:

【参考方案1】:

似乎错误日志指向view(在第 3 行)

java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter view

我认为那些parent: AdapterView&lt;*&gt;view: View 是可为空的类型。 因此需要为该类型添加 null 安全调用运算符

binding.inventoryAddEditProductGroupSpinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener

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

         override fun onNothingSelected(parent: AdapterView<*>?)
         
     

【讨论】:

Putra,谢谢 - 这就是问题所在。由于 LiveData 的工作方式,我知道它正在发生,但我认为它不会像那样影响 AdapterView。非常感谢。 太好了,很高兴它有帮助!【参考方案2】:

您可以简化和清理您的代码。 只需将所选位置传递给您的viewmodel

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

viewmodel 类中编写主要业务逻辑。像下面这样

fun updateCurrentProductGroup(position: Int)
    // here you can do what you want
    // example 
    val productGroupObject = filteredAppDataProductGroups.value[position]
    if (productGroupObject.productGroupID.isNotEmpty())
            businessViewModel.updateCurrentProductGroupVMLiveData(productGroupObject.productGroupID)
    

【讨论】:

感谢您对 Jakir 的回答,但我要换掉填充 Spinner 的整个列表,而不仅仅是列表中的项目。问题还与 LiveData 如何使上述视图为空有关。

以上是关于Spinner 侦听器 LiveData 问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 Onitemselect 侦听器从微调器调用另一个活动。 [关闭]

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

如果选择了非零位置,则在旋转后调用 Spinner 的 onItemSelected 回调两次

如何在MVVM架构中观察RecyclerView适配器中的LiveData?

spinner的理解

如果尚未添加侦听器并且侦听器处理程序是匿名函数,则在 nodeJS 中添加侦听器