I have a problem with getting data from check_list_table
. insert
method executes normally and there is no error or warning, but allItems
property doesn't work.
Item, ItemDao and ViewModel class are shown below:
@Entity(tableName = "check_list_table")
data class Item(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
var title: String,
var priority: Int=0
)
interface ItemDao {
@Insert
suspend fun insert(item: Item)
@Delete
suspend fun delete(item: Item)
@Query("SELECT * FROM check_list_table ORDER BY id DESC")
fun getAllItems():LiveData<List<Item>>
}
class DailyCheckListItemViewModel(private val itemDao: ItemDao, application: Application) :
AndroidViewModel(application) {
private val viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
val allItems = itemDao.getAllItems().value
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
}
fun onAdd(item: Item) {
uiScope.launch {
insertItem(item)
}
}
suspend fun insertItem(item: Item) {
withContext(Dispatchers.IO) {
itemDao.insert(item)
}
}
}
insert
method called.insert
method called with a proper feed.insert
method is called from a non-ui threadWhy I cant getData from database [using allItems Property]?
You've defined an observable read operation:
@Query("SELECT * FROM check_list_table ORDER BY id DESC")
fun getAllItems():LiveData<List<Item>>
But are reading it in a direct manner:
val allItems = itemDao.getAllItems().value
This will not work because the LiveData
object must be observed to actually trigger the database read.
You can either ...
Make the read operation a "one-shot" (non-observable) operation (if you only need to read the data once)
Change the DAO
to just return a list of items, not a LiveData
:
@Query("SELECT * FROM check_list_table ORDER BY id DESC")
suspend fun getAllItems():List<Item>
And change the ViewModel
to fetch that data all at once:
viewModelScope.launch(Dispatchers.IO){ allItems = itemDao.getAllItems() }
Or make the ViewModel
variable a LiveData
as well and observe it in the UI (if the data can change and you want to refresh the UI as it does)
The DAO
stays the same:
@Query("SELECT * FROM check_list_table ORDER BY id DESC")
fun getAllItems():LiveData<List<Item>>
The ViewModel just references the LiveData
:
val allItems = itemDao.getAllItems()
And your Activity
/Fragment
observes the changes. Now that the LiveData
is being observed, the read operation will be triggered and the data returned:
viewModel.allItems.observe(/*lifecycle*/) { items ->
// Do something with the list of items that was read
}