linucksrox
linucksrox

Reputation: 150

How can I listen for onCheckedChangeListener in a RecyclerView using MVVM?

I'm attempting to write a basic Todo list in Kotlin but wanted to use the recommended best practices and Android architecture components. At this point I have the basic architecture set up and there is a RecyclerView list of items stored in the database with a checkbox on the left side, and a description to the right. So far the list automatically updates when new data is added (via the floating action button). Now I want to update the record immediately whenever the checkbox is clicked for a particular item.

I can't figure out how or where to set the checkbox listener in order to pass the checked state and the item id to the ViewModel in order to update the data in the database. I thought about defining the listener directly inside the adapter, but then I can't find any way to call my ViewModel's update method. But then if I set up the listener in the fragment and pass that to the adapter, I can't find a way to get the id of the item.

todo list screenshot

This is my current fragment:

class ChecklistFragment : Fragment() {

    private lateinit var checklistViewModel: ChecklistViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_checklist, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Set up RecyclerView
        items_list.layoutManager = LinearLayoutManager(activity)
        val adapter = ToDoItemAdapter(object: CompoundButton.OnCheckedChangeListener {
            override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
                Toast.makeText(activity, "checked", Toast.LENGTH_SHORT).show()
            }
        })
        items_list.adapter = adapter

        // Set up ViewModel
        checklistViewModel = ViewModelProviders.of(this).get(ChecklistViewModel::class.java)
        checklistViewModel.allToDoItems.observe(this, Observer { toDoItems ->
            toDoItems?.let { adapter.setToDoItems(it) }
        })

        // Set up fab
        add_list_item_fab.setOnClickListener {
            checklistViewModel.insert(ToDoItem(description = "Item ${Random.nextInt(1,999)}", checked = Random.nextBoolean()))
        }
    }
}

This is my current adapter:

class ToDoItemAdapter(val onCheckedChangeListener: CompoundButton.OnCheckedChangeListener) : RecyclerView.Adapter<ToDoItemAdapter.ViewHolder>() {

    private var toDoItems = emptyList<ToDoItem>()

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val checkbox: CheckBox = view.checkbox
        val tvDescription: TextView = view.tv_description

        fun bind(position: Int) {
            checkbox.isChecked = toDoItems[position].checked
            checkbox.setOnCheckedChangeListener(onCheckedChangeListener)
            tvDescription.text = toDoItems[position].description
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.checklist_item, parent, false)
        return ViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(position)
    }

    override fun getItemCount() = toDoItems.size

    internal fun setToDoItems(toDoItems: List<ToDoItem>) {
        this.toDoItems = toDoItems
        notifyDataSetChanged()
    }
}

What is a best practice approach to listening to checked items and immediately storing those changes in the database using the MVVM architecture?

Upvotes: 1

Views: 1656

Answers (1)

MJ Studio
MJ Studio

Reputation: 4611

If you want to click or check something in RecyclerView Item,

There is a elegant way for that.

class MyAdapter(val viewModel : ViewModel) : RecyclerView.ViewModel<ViewHolder>{

fun onCreateViewModel(..){
     val binding = ItemRecyclerViewBinding.inflate(LayoutInflater.from(parent.context), parent,false)
    binding.vm = viewModel
}
}

in XML

<data>
    <variable name="vm" type="YourViewModel"/
    <variable name="yourItem" type="YourItem"/
</data>
<FrameLayout or something
    android:onClick = "@{(view) -> vm.onClickItem(view, yourItem)}">

</FrameLayout>

in ViewModel Class,

fun onClickItem(view : View, yourItem : YourItem){
    Log.e(TAG,"$view is clicked with $yourItem")
}

I write about how to listen click or check event from recyclerview items

If you want how to store these datas to DB, you can use your own routine for that in ViewModel Class

Happy coding!

Upvotes: 1

Related Questions