I'm developing MVVM kotlin application with repository pattern
I have separated my model classes as below
classes represents the data coming from network
classes represents entities for the room database
classes that represents the domain
In my repository I want always to return the domain object not the network object or the entity object.
In my Dao I insert and retrieve entity object as below
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAsteroids(asteroid: List<AsteroidEntity>)
#Query("SELECT * FROM asteroid_tbl")
fun getAsteroidsFromDb () : LiveData<List<AsteroidEntity>>
And I have a function in the repository that returns the list of asteroids as Live data from room as below
override suspend fun getAsteroids(): LiveData<List<Asteroid>> {
return appLocalDb.asteroidDao.getAsteroidsFromDb()
}
But the issue is the dao returns a LiveData<List<AsteroidEntity>>
while the repository I want it to return the domain model as
LiveData<List<Asteroid>>
Any suggestion on how to solve this problem?
Use Transformations.map
override suspend fun getAsteroids(): LiveData<List<Asteroid>> {
return Transformations.map(appLocalDb.asteroidDao.getAsteroidsFromDb()) { it.map{ item -> Asteroid(item.name,....)} }
}
For Further Documentation checkout the docs
https://developer.android.com/reference/android/arch/lifecycle/Transformations
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'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.
How can I do a room transaction across 2 different DAOs usin rxjava?
I have this code that I would like to use with Rxjava but I need it to return some kind of observable
#Transaction
fun insertStoreWithPictures(store: Store, pictures: List<StorePicture>) {
insertStore(store)
insertPictures(pictures)
}
The store DAO
#Dao
abstract public class store {
#Insert
Single<Long> insert(store entity);
}
The storePicture DAO
#Dao
abstract public class storePicture {
#Insert
Completable insert(storePicture... entity);
}
I think you can use zip or combine operator of RxJava. It would create an observable from an iterators observable source.
Best example you can follow to achieve the same - https://blog.mindorks.com/understanding-rxjava-zip-operator-with-example
I'm developing an android app with Kotlin.
I'm using RxJava and MVVM.
i tried this :
a link
Here is one of my method in DataSource interface
fun insertPhoneNumber(phoneNumber: PhoneNumber) : Long
fun insertAllPhoneNumber(phoneNumberList: List<PhoneNumber>): List<Long>
The question is, after building the basic classes and requirements.
The compiler issues an error as follows:
e: [kapt] An exception occurred: java.lang.IllegalArgumentException:
long cannot be converted to an Element
I want to return the corresponding ID when a record is stored in my table
If you're using RxJava your Dao interface should look like this...
#Dao
interface WhateverDao {
#Insert
fun insertPhoneNumber(phoneNumber: PhoneNumber) : Maybe<Long>
#Insert
fun insertAllPhoneNumber(vararg phoneNumberList: PhoneNumber): Maybe<List<Long>>
}
Changes are:
Mark the interface with #Dao
Mark insert methods with #Insert
Pass a vararg to the insert all method
Use RxJava classes on the return type to make use of the reactive-streams pattern
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.