【问题标题】:Unable to get ViewModel instance in RecyclerView.Adapter class Kotlin无法在 RecyclerView.Adapter 类 Kotlin 中获取 ViewModel 实例
【发布时间】:2019-08-19 16:01:19
【问题描述】:

我是 Kotlin 的新手,正在尝试创建一个闹钟应用。在这个应用程序中,我使用的是 LiveData 和 RecycleView。现在我需要更改警报状态:

这是我的 AlarmsRecyclerAdapter,我尝试在其中创建 .onClickListener{}

override fun onBindViewHolder(holder: AlarmsRecyclerAdapter.AlarmItemHolder, position: Int) {
        //mAlarmViewModel = ViewModelProviders.of( context as Fragment)[AlarmViewModel::class.java]
        if (mAlarms != null) {
            val current = mAlarms!!.get(position)
            holder.view.edit_time_button.text = current.printTime()
            holder.view.switch_alarm_enabled.isEnabled = current.enabled

            holder.view.switch_alarm_enabled.setOnClickListener {
                current.enabled = !current.enabled
               // mAlarmViewModel.insert(current)
            }
        } else {
            // Covers the case of data not being ready yet.
            holder.view.edit_time_button.text = "no timer"
        }
    }

我还尝试在注释行中获取 ViewModel 的实例,但它只会引发类似

的错误

java.lang.ClassCastException: android.app.Application 无法转换为 androidx.fragment.app.FragmentActivity 在 com.xxx.alarm.AlarmsRecyclerAdapter.onBindViewHolder(AlarmsRecyclerAdapter.kt:58) 在 com.xxx.alarm.AlarmsRecyclerAdapter.onBindViewHolder(AlarmsRecyclerAdapter.kt:33)

我需要更改数据库中的警报,那么如何在适配器类中获取ViewModel 的实例?还是有更好的方法来管理数据变化?

【问题讨论】:

    标签: android mvvm kotlin android-recyclerview


    【解决方案1】:

    不确定是否将 ViewModel 放入 RecyclerView,也不确定这是否是最佳实践。但这是我这样做的方式,并且有其他人看到这样做。 首先,您在 Fragment 中创建 ViewModel。 然后您观察您的 AlarmData,当它发生变化时,您会更新 RecyclerAdapter 中的数据。

    所以在你的 Fragment 中你可以做这样的事情():

    mAlarmViewModel = ViewModelProviders.of( context as Fragment)[AlarmViewModel::class.java]
    mAlarmViewMode.getAlarms().observe(...
        mAdapter.setData(newData)
    

    然后在适配器内部添加以下内容:

    setData(data:List) {
        mAlarms= data;
        notifyDataSetChanged();
    }    
    

    这应该让您的数据保持更新。

    现在更改您的数据。 尝试在 ViewHolder 中设置 OnclickListener,因为这会提高应用程序的速度。 要获得您当前的价值,您可以这样做:

    val current = mAlarms!!.get(getAdapterPosition())
    

    最后你应该为你的适配器添加一个接口,像这样:

    interface ItemSelectedListener {
      fun onItemSelected(item:Any, v:View)
    }
    

    从您的 Fragment 设置此接口并从 onClickListener 调用它。 然后,您在 Fragment 中拥有所需的所有数据,并且可以从那里修改它

    【讨论】:

    • 感谢您的回复。实际上我需要在数据库中更改我的警报,所以这就是我需要 ViewModel 实例的原因。如果我在数据库中更改它们,由于LiveData,它应该在前端更改。
    • 所以我猜你也在使用 Room 和 LifeData?当您更改数据库中的某些内容时,来自 LifeDataObject 的 Observer 将触发,并更新您的 recyclerview。
    • 是的,你是对的。但我无法获得ViewModel 的实例来使用像mAlarmViewModel.insert(current) 这样的数据库。在Fragment 类中,我可以通过这种方式获取实例mAlarmViewModel = ViewModelProviders.of(this)[AlarmViewModel::class.java],但我需要将一些参数传递给方法.of() 以获取AlarmsRecyclerAdapter 类中的实例。
    • 就像我说的,您可以将数据修改移动到您的 Fragment,在那里您将拥有所需的一切。如果您确实需要在 Recyclerview 中获取 ViewModel,只需在构造函数中将 Fragment 作为附加参数传递并使用此引用即可获取 ViewModel。
    • 看看这个 Gist:gist.github.com/glm9637/db7c702074514718b34796e462be44a1 我不精通 Kotlin,但希望对您有所帮助。
    猜你喜欢
    • 2018-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2017-12-13
    相关资源
    最近更新 更多