Step #12: Making Another Motor
Now, let’s create another ViewModel
implementation that uses the same pattern as RosterMotor
, but for a single model based on its ID. We can use this both for DisplayFragment
and the EditFragment
that we will create in the next tutorial.
Right-click over the com.commonsware.todo
package in the java/
directory and choose “New” > “Kotlin File/Class” from the context menu. For the name, fill in SingleModelMotor
, then choose “Class” for the kind. Then press Enter or Return to create the empty SingleModelMotor
class.
Then, replace its contents with:
package com.commonsware.todo
import androidx.lifecycle.ViewModel
class SingleModelMotor(
private val repo: ToDoRepository,
private val modelId: String
) : ViewModel() {
}
Like RosterMotor
, this takes a ToDoRepository
as a constructor parameter. Unlike RosterMotor
, this also takes the ID of the ToDoModel
that we want to use, as another constructor parameter.
To actually retrieve the ToDoModel
for this ID, we could just rummage through repo.items
here in RosterMotor
. It will be cleaner to have ToDoRepository
do this. So, add this find()
function to ToDoRepository
:
fun find(modelId: String) = items.find { it.id == modelId }
Right now, all this does is scan through the items
list and find the matching ToDoModel
. Later on, we will do a database query to find the to-do item in the database.
Then, add a corresponding getModel()
function to SingleModelMotor
:
fun getModel() = repo.find(modelId)
This just uses the repo
and modelId
to retrieve the ToDoModel
and returns it.
We need to teach Koin about this viewmodel, the same way that we did with RosterMotor
. So, in ToDoApp
, add this line to the koinModule
declaration:
viewModel { (modelId: String) -> SingleModelMotor(get(), modelId) }
This is a bit different than the viewModel()
call to set up RosterMotor
:
viewModel { RosterMotor(get()) }
This time, we want to provide a parameter when we retrieve the SingleModelMotor
: the model ID of the ToDoModel
that we want to display. Koin has no way of getting this value on its own, the way it can for the ToDoRepository
singleton. So, we set up the lambda expression to return a function type, one that takes our modelId
as a parameter and uses it to construct the SingleModelMotor
instance.
Then, in DisplayFragment
, add this property:
private val motor: SingleModelMotor by viewModel { parametersOf(args.modelId) }
This time, instead of just using by viewModel()
, we use a variant that employs parametersOf()
to supply the parameters that get passed to our function type that we used in the Koin declaration. Here, we get the modelId
out of our Navigation component arguments, wrap them using parametersOf()
, and use that to set up the SingleModelMotor
. The net result is that the model ID that we had in RosterListFragment
— from when the user clicked the row — winds up in the hands of our viewmodel, and from there can be used to get the ToDoModel
.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.