In my app I have a list of workouts, and at one point a want to get the name of one workout using its id in the Room database. For this, I made a SQL query in the DAO class to get the workout name using its id. my main problem is how to get it from the ViewModel
to the view. The app uses coroutines.
DAO function:
@Query(
"SELECT workout_name FROM workout_table "
"WHERE id = :workoutId"
)
suspend fun getWorkoutName(workoutId: Long): String
Repository function:
@WorkerThread
suspend fun getWorkoutName(workoutId: Long): String {
return database.workoutDao().getWorkoutName(workoutId)
}
ViewModel function:
fun getWorkoutName(workoutId: Long): MutableLiveData<String> {
val workoutName = MutableLiveData<String>()
CoroutineScope(Dispatchers.IO).launch {
workoutName.postValue(repository.getWorkoutName(workoutId))
}
return workoutName
}
View function (inside the fragment .kt class):
private fun setUpAppBar() {
binding?.apply {
viewModel.getWorkoutName(currentWorkoutId!!).observe(viewLifecycleOwner) {
editWorkoutTopAppbar.title = it
}
}
}
Assume 'editWorkoutTopAppbar' is a textView.
This code works, but notice the ViewModel
and the view. In the ViewModel
I return a MutableLiveData
variable and observe it in the view, I do this to use the variable when the value is ready.
I realize I can get all the workouts at the beginning of the app and filter them to get the specific one, but my goal is to query the database.
What is a cleaner or more efficient way to get this value from the ViewModel
?
CodePudding user response:
In my projects with LiveData and ViewModel I utilise DataBinding for this. I set the ViewModel
as a variable inside the xml and bind the variables of the ViewModel
to the views:
<layout>
<data>
<variable
name="viewModel"
type="path.ViewModel" />
</data>
<TextView
android:text="@{viewModel.variableName}" />
</layout>
Fragment:
val binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
binding.setVariable(BR.viewModel, viewModel)
Possible code improvement:
You could also directly return a LiveData
from your Dao:
Dao:
@Query(
"SELECT workout_name FROM workout_table "
"WHERE id = :workoutId"
)
fun getWorkoutName(workoutId: Long): LiveData<String>
Repo:
fun getWorkoutName(workoutId: Long): LiveData<String> =
database.workoutDao().getWorkoutName(workoutId)
ViewModel:
// would always return only a LiveData instead of MutableLiveData so only the ViewModel can manipulate its value
fun getWorkoutName(workoutId: Long): LiveData<String> =
workoutName.postValue(repository.getWorkoutName(workoutId))
On Coroutines:
Inside a ViewModel
you can also use viewModelScope
for Coroutines.