I am trying to get list of todos from database with livedata however, while debugging it always shows null for value. I have provided my files below.
My Dao:
@Query("SELECT * FROM todo_table WHERE IIF(:isCompleted IS NULL, 1, isCompleted = :isCompleted)")
fun getTodos(isCompleted: Boolean?): LiveData<List<Todo>>
My ViewModel:
private var _allTodoList = MutableLiveData<List<Todo>>()
var allTodoList: LiveData<List<Todo>> = _allTodoList
init {
viewModelScope.launch(Dispatchers.IO) {
val list = todoRepository.getTodos(null)
_allTodoList.postValue(list.value)
}
}
fun onFilterClick(todoType: Constants.TodoType) {
when (todoType) {
Constants.TodoType.ALL -> {
viewModelScope.launch(Dispatchers.IO) {
val list = todoRepository.getTodos(null)
_allTodoList.postValue(list.value)
}
}
Constants.TodoType.COMPLETED -> {
viewModelScope.launch(Dispatchers.IO) {
val list = todoRepository.getTodos(true)
_allTodoList.postValue(list.value)
}
}
Constants.TodoType.INCOMPLETE -> {
viewModelScope.launch(Dispatchers.IO) {
val list = todoRepository.getTodos(false)
_allTodoList.postValue(list.value)
}
}
}
}
My MainActivity:
val allTodoList = viewModel.allTodoList.observeAsState()
allTodoList.value?.run {//value is always null
if (!isNullOrEmpty()) {
...
} else {
...
}
}
While debugging I found that allTodoList.value
is always null however, when I manually run same query in app inspection I the get the desired results.
CodePudding user response:
You can simplify your code, see if it works. ViewModel only needs this:
val allTodoList: LiveData<List<Todo>> = todoRepository.getTodos(null)
MainActivity:
val allTodoList by viewModel.allTodoList.observeAsState()
if (!allTodoList.isNullOrEmpty()) {
...
} else {
...
}
CodePudding user response:
I think that you are not listening long enough to the LiveData you get from Room, so you only get the initial value, which is always null.
A possible solution would be to set the todo type as a live data itself and use a switchMap transformation in the ViewModel :
private val todoType = MutableLiveData<Constants.TodoType>(Constants.TodoType.ALL)
val allTodoList: LiveData<List<Todo>> = androidx.lifecycle.Transformations.switchMap(todoType) { newType ->
val typeAsBoolean = when(newType) {
Constants.TodoType.ALL -> null
Constants.TodoType.COMPLETED -> true
Constants.TodoType.INCOMPLETE -> false
else -> throw IllegalArgumentException("Not a possible value")
}
// create the new wrapped LiveData
// the transformation takes care of subscribing to it
// (and unsubscribing to the old one)
todoRepository.getTodos(typeAsBoolean)
}
fun onFilterClick(todoType: Constants.TodoType) {
// triggers the transformation
todoType.setValue(todoType)
}
It is in fact the exact use case demonstrated in the reference doc