Step #5: Completing the Adapter and ViewHolder
Now, we can start filling in the implementations of those stub methods in our RosterAdapter
, plus get our RosterRowHolder
working.
The job of onCreateViewHolder()
is to create instances of a ViewHolder
, including working with the ViewHolder
to set up the widgets. Since our widgets are defined in a layout resource, we will need a LayoutInflater
to accomplish this. The best way to get a LayoutInflater
is to call getLayoutInflater()
on an activity or fragment… but RosterAdapter
has none of these.
So, add a constructor parameter to RosterAdapter
to take in a LayoutInflater
:
class RosterAdapter(private val inflater: LayoutInflater) :
ListAdapter<ToDoModel, RosterRowHolder>(DiffCallback) {
Then, modify onCreateViewHolder()
in RosterAdapter
to be:
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
) = RosterRowHolder(TodoRowBinding.inflate(inflater, parent, false))
Here, we are using inflate()
on the generated TodoRowBinding
class to not only inflate the todo_row
layout, but also to set up the binding object we can use to populate that row’s widgets. The particular flavor of inflate()
that we are calling says:
- Use this
LayoutInflater
to inflate the layout resource (host.getLayoutInflater()
) - The widgets in that layout resource eventually will be children of a certain parent (
parent
)… - …but do not add them as children right away (
false
)
(some container classes, like RelativeLayout
, really need to know their parent in order to work properly, so we use this standard recipe for calling inflate()
)
However, onCreateViewHolder()
will have a compile error, as we are passing a constructor parameter to RosterRowHolder
that does not exist. So, modify RosterRowHolder
to look like this:
package com.commonsware.todo
import androidx.recyclerview.widget.RecyclerView
import com.commonsware.todo.databinding.TodoRowBinding
class RosterRowHolder(private val binding: TodoRowBinding) :
RecyclerView.ViewHolder(binding.root) {
}
getRoot()
on a binding object returns the root widget of the inflated layout, which in our case is the ConstraintLayout
. We need to pass that to the ViewHolder
constructor, so this change fixes that compile error that we had from when we originally set up this class.
Now our RosterAdapter
knows to create RosterRowHolder
objects as needed. However, somewhere, we need to get a ToDoModel
object and fill in the text and is-completed state for the CheckBox
.
With that in mind, modify onBindViewHolder()
on RosterAdapter
to look like this:
override fun onBindViewHolder(holder: RosterRowHolder, position: Int) {
holder.bind(getItem(position))
}
onBindViewHolder()
is called when RecyclerView
wants us to update a ViewHolder
to reflect data from some item in the RecyclerView
. We are given the position
of that item, along with the RosterRowHolder
that needs to be updated. Since RosterAdapter
extends ListAdapter
, we have a getItem()
function that gives us our ToDoModel
for a given position, and we pass that to a bind()
function on RosterRowHolder
.
This will have a compile error, as there is no bind()
function on RosterRowHolder
. The objective of bind()
is to populate our widgets, and since we are using the data binding framework, that comes in the form of calling binding methods on the TodoRowBinding
object.
So, add a bind()
function to RosterRowHolder
:
fun bind(model: ToDoModel) {
binding.apply {
isCompleted.isChecked = model.isCompleted
desc.text = model.description
}
}
Here, we use our binding
property to access each of our widgets and update their states to match that of the associated ToDoModel
.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.