I'm posting my room query result using the below code
_data.postValue(databaseImpl.findRepoById(id).value)
But it seems the returned object is empty. I'm guessing we need to observe databaseImpl.findRepoById(id), not access it directly but since it's in a viewmodel I don't have a lifecycleOwner to assign to the room query livedata.
databaseImpl.observe(this, Observer { //!!this is modelview and not activity
_data.postValue()
})
What is the right way to use Room query and update a mediator live data?
You could try use coroutines to query your data so you can have something like this for your DAO:
#Query("SELECT * FROM users")
fun findRepoById(id): Flow<User>
In your DatabaseImpl class return have it as:
fun findRepoById(id): Flow<User> = userDao.findRepoById(id)
Then in your ViewModel you could do this:
viewModelScope.launch {
databaseImpl.findRepoById(id).map { _data.postValue(it) }
}
Have a look at this article Room and Coroutines by Florina Muntenescu
on how you could set up coroutines and use it with room.
Related
I am using Room and I have written the Dao class as follows.
Dao
#Dao
interface ProjectDao {
#Query("SELECT * FROM project")
fun getAllProjects(): Flow<List<Project>>
...etc
}
and this Flow is converted to LiveData through asLiveData() in ViewModel and used as follows.
ViewModel
#HiltViewModel
class MainViewModel #Inject constructor(
private val projectRepo: ProjectRepository
) : ViewModel() {
val allProjects = projectRepo.allProjects.asLiveData()
...
}
Activity
mainViewModel.allProjects.observe(this) { projects ->
adapter.submitList(projects)
...
}
When data change occurs, RecyclerView is automatically updated by the Observer. This is a normal example I know.
However, in my project data in Flow, what is the most correct way to get the data of the position selected from the list?
I have already written code that returns a value from data that has been converted to LiveData, but I think there may be better code than this solution.
private fun getProject(position: Int): Project {
return mainViewModel.allProjects.value[position]
}
Please give me suggestion
Room has in built support of flow.
#Dao
interface ProjectDao {
#Query("SELECT * FROM project")
fun getAllProjects(): Flow<List<Project>>
//lets say you are saving the project from any place one by one.
#Insert()
fun saveProject(project :Project)
}
if you call saveProject(project) from any place, your ui will be updated automatically. you don't have to make any unnecessary call to update your ui. the moment there is any change in project list, flow will update the ui with new dataset.
to get the data of particular position, you can get it from adapter list. no need to make a room call.
I am using live data with room database and my activity observes live data provided from room database.
#Query("SELECT * FROM BUS WHERE BUS_CATEGORY = :busCategory")
LiveData<List<Bus>> getLiveBuses( String busCategory);
ViewModels gets LiveData via Dao(Data Access Object) and activity observes this live data.
Now it works fine. But when busCategory changes i can't modify this live data to get buses for newly selected busCategory.
So how can i observe this same liveData where query parameters is changeable?
I suggest you to to use viewModel. I did the query and observe changes using MutableLiveData.
First step
val mutableBusCategory: MutableLiveData<String> = MutableLiveData()
Setter for mutablelivedata
fun searchByCategory(param: String) {
mutableBusCategory.value = param
}
observable to observe the change
val busObservable: LiveData<Bus> = Transformations.switchMap(mutableBusCategory) { param->
repository.getLiveBuses(param)
}
and final step to observe the live data
busObservable.observe(this, Observer {
//your logic for list})
and to trigger mutablelivedata
searchByCategory(//categoryName)
I don't think this is a reasonable expectation. It would make more sense to fire off a new query and subscribe to that.
I'm using Room to handle my local database, and LiveData to handle the DAOs.
So I'm using LiveData as thread handler for my transactions.The question is how can I do insert and updates with LiveData? Or generally how can void functions return LiveData in the Room?
#Query("select * from table")
fun getAll(): LiveData<List<T>>
#Insert
fun insert(T data): LiveData<?> // What should be the generic, since it's void?
In RxJava we have something like this:
#Insert
fun insert(T data);
The question is how can I do insert and updates with LiveData? Or generally how can void functions return LiveData in the Room?
You can't use LiveData object itself to insert or update data in your database (db). LiveData is a wrapper around the object loaded from db which can be observed.
In order to perform insert/update operations you need to pass the object annotated with #Entityannotation to your DAO method parameter. You can do it either by calling LiveData#getValue(), or observe the LiveData in Activity, or Fragment and update a local variable via the observer and pass said variable.
I am using Component libraries in my android app. in some case it is needed to use Livedata and observe its data but sometimes I just want to get some ordinary list not Livedata , How can I do that? query DB in simple way
p.s : I use getValue() but it returns null
Use query like this in DAO:
#Query("SELECT * FROM TABLE_NAME")
fun getListOfData(): List<Data>?
this will provide you list of data from your table, just like the select query passed in #Query parameter.
Edit:
When calling from main thread, you can use handler to do your job in background like below:
//Method from where you want your data from Db.
fun getMyList() {
Thread {
(your db object).(your dao).getListOfData()
}.start()
}
or you can allow your db to execute on main thread when building your room db like below (Though i wouldn't recommend this) :
Room.databaseBuilder(
...
)
.allowMainThreadQueries()
.build()
You can simply write query in your Dao which has return type as List and call from your ViewModel where you need those data.
Example :
//YourDao
#Query("SELECT * FROM YourTable")
List<YourModel> getAllYourTableData();
//YourRepo
public static List<YourModel> getAllData(){
return getYourModelDao.getAllYourTableData();
}
//Your ViewModel
public void someFunctionWhereYouNeedNormalData(){
//assign to list
YourRepo.getAllData();
}
Assuming you have knowledge about repo pattern in android arch components.
I am currently applying Room + ViewModel + LiveData to my project.
In my app, there is "obviously" observe data that is needed, but not all.
The code below is example code for category data. In my situation, category data does not change and always maintains the same value state (13 categories and content does not change). Categories are data that is loaded from the Database through the CategoryItemDao class.
Does category data need to be wrapped with livedata?
Or is there a reason enough to use LiveData in addition to its observerable feature?
I've read the guide to LiveData several times, but I do not understand the exact concept.
CategoryItemDao
#Dao
interface CategoryItemDao {
#Query("SELECT * FROM CategoryItem")
fun getAllCategoryItems(): LiveData<MutableList<CategoryItem>>
}
CategoryRepository
class CategoryRepository(application: Application) {
private val categoryItemDao: CategoryItemDao
private val allCategories: LiveData<MutableList<CategoryItem>>
init {
val db = AppDatabase.getDatabase(application)
categoryItemDao = db.categoryItemDao()
allCategories = categoryItemDao.getAllCategoryItems()
}
fun getAllCategories() = allCategories
}
CategoryViewModel
class CategoryViewModel(application: Application) : AndroidViewModel(application) {
private val repository = CategoryRepository(application)
private val allCategories: LiveData<MutableList<CategoryItem>>
init {
allCategories = repository.getAllCategories()
}
fun getAllCategories() = allCategories
}
This is fine, but you can make a few changes:
Change LiveData<MutableList<CategoryItem>> to LiveData<List<CategoryItem>>. Don't use a MutableList unless you really have to. In your case, List would work fine.
In your CategoryRepository instead of fetching in init, do it during the getAllCategories() call. So change your code like this: fun getAllCategories() = categoryItemDao.getAllCategoryItems()
Similarly do the same in CategoryViewModel as well. Change you code to: fun getAllCategories() = repository.getAllCategories()
A common misconception is to use LiveData only when the data changes. But that's not true. Your 13 categories may not change, but that's in a database. So if you were to accomplish this without a LiveData you have to query the DB and populate the view in the main thread, or you need to wrap this around in a background thread. But if you do this via LiveData, you get the Asynchronous Reactive way of coding for free. Whenever possible, try to make your view observe a LiveData.