Michael
Michael

Reputation: 111

Unable to get ViewModel instance in RecyclerView.Adapter class Kotlin

I'm new to Kotlin and trying to create an alarm clock app. In this app I'm using LiveData and RecycleView. Right now I need to change the alarm status:

switcher

Here is my AlarmsRecyclerAdapter where i tried to create .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"
        }
    }

I also tried to get instance of ViewModel in the comment line, but it just throws errors like

java.lang.ClassCastException: android.app.Application cannot be cast to androidx.fragment.app.FragmentActivity at com.xxx.alarm.AlarmsRecyclerAdapter.onBindViewHolder(AlarmsRecyclerAdapter.kt:58) at com.xxx.alarm.AlarmsRecyclerAdapter.onBindViewHolder(AlarmsRecyclerAdapter.kt:33)

I need to change the alarms in the database, so how can I get an instance of ViewModel in the adapter class? Or is there better way to manage the data changing?

Upvotes: 3

Views: 7363

Answers (1)

glm9637
glm9637

Reputation: 894

Not really sure about getting your ViewModel inside your RecyclerView, and not really sure if this would be considered best practice. But here is the way I am doing this, and have others seen doing it. First you create your ViewModel in you Fragment. Then you observe your AlarmData and when it changes you update the data in your RecyclerAdapter.

So in your Fragment you do something like this():

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

and inside you Adapter you add the following:

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

this should keep your data updated.

Now for the changing of your data. Try Setting the OnclickListener inside your ViewHolder, as this is going to increase the speed of your app. to get your current value you could do this:

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

Finally you shold add a Interface to your Adapter, something like this:

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

Set this interface from your Fragment and call it from the onClickListener. Then you have all the data you need inside your Fragment and can modify it from there

Upvotes: 5

Related Questions