Step #2: Passing the Event Up the Chain
Eventually, we need to modify our repository to reflect the change in the model state.
We could have the RosterRowHolder
do that. However, it is best to minimize the number of places that you are modifying your data. The more your model-manipulating code is scattered, the more difficult it will be to change that code, such as when we want to start storing this stuff in a database. Since we already are working with the repository in RosterMotor
, we may as well have it handle the model modifications as well.
However, our RosterRowHolder
does not have access to the RosterMotor
. We could pass it down from the RosterListFragment
if we wanted. Alternatively, we can pass the event up the Kotlin object hierarchy, from the RosterRowHolder
through the RosterAdapter
to the RosterListFragment
, and from there affect our RosterMotor
.
With that in mind, modify the constructor of RosterRowHolder
to look like:
class RosterRowHolder(
private val binding: TodoRowBinding,
val onCheckboxToggle: (ToDoModel) -> Unit
) :
Here, onCheckboxToggle
is a function type. We are passing some sort of function or lambda expression into RosterRowHolder
that takes a ToDoModel
as input and returns nothing (i.e., Unit
, roughly analogous to void
in Java).
Then, revise bind()
on RosterRowHolder
to look like:
fun bind(model: ToDoModel) {
binding.apply {
isCompleted.isChecked = model.isCompleted
isCompleted.setOnCheckedChangeListener { _, _ -> onCheckboxToggle(model) }
desc.text = model.description
}
}
Now, our setOnCheckedChangeListener()
calls the onCheckboxToggle
function type, passing in the current model. This replaces the TODO()
that we used in the previous step.
Now, though, RosterAdapter
will have a compile error, as we are not passing in this value. So, add a similar constructor parameter to RosterAdapter
:
class RosterAdapter(
private val inflater: LayoutInflater,
private val onCheckboxToggle: (ToDoModel) -> Unit
) :
Then, pass onCheckboxToggle
to the RosterRowHolder
constructor call in onCreateViewHolder()
:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
RosterRowHolder(
TodoRowBinding.inflate(inflater, parent, false),
onCheckboxToggle
)
So now we are passing the onCheckboxToggle
that the RosterAdapter
receives to each of the RosterRowHolder
instances. This, though, has broken RosterListFragment
, as it is not passing a value for onCheckboxToggle
in its RosterAdapter
constructor call.
To fix this, modify the creation of the RosterAdapter
instance in RosterListFragment
to look like:
val adapter = RosterAdapter(layoutInflater) { model ->
TODO()
}
When a function type is the last parameter for a function call, we can use a lambda expression outside of the function call parentheses. So, the lambda expression that we have here turns into onCheckboxToggle
.
Right now, we have a TODO()
function call in the lambda expression. So, if you run the app and you click on one of the CheckBox
widgets… you crash with a error of:
kotlin.NotImplementedError: An operation is not implemented.
However, this is an expected crash. NotImplementedError
is what TODO()
throws. So, this confirms that we got control in RosterListFragment
when the user clicked the CheckBox
. Now, we need to replace the TODO()
with something more useful and less crash-prone.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.