My dao looks like
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(group: Group): Completable
#Query("DELETE FROM groups")
fun deleteAllGroups()
I would like to refresh all rows like
#Transaction
fun refreshGroups(groups: List<Group>): Completable {
deleteAllGroups()
insertAll(groups)
}
However, I can't return Completable from Transaction.
I'm using Rx so I'm expecting some kind of Observable.
Related
I am following DAO tutorial on Android developers here:
https://developer.android.com/codelabs/android-room-with-a-view-kotlin#5
They say:
By default, all queries must be executed on a separate thread.
Room has Kotlin coroutines support. This allows your queries to be annotated with the suspend modifier and then called from a coroutine or from another suspension function.
Dao interface is as follows:
#Dao
interface WordDao {
#Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): List<Word>
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)
#Query("DELETE FROM word_table")
suspend fun deleteAll()
}
Why getAlphabetizedWords() is not defined as suspend function?
In coroutines, a flow is a type that can emit multiple values sequentially, as opposed to suspend functions that return only a single value. For example, you can use a flow to receive live updates from a database.
#Dao
interface WordDao {
// The flow always holds/caches latest version of data. Notifies its observers when the
// data has changed.
#Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): Flow<List<Word>>
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)
#Query("DELETE FROM word_table")
suspend fun deleteAll()
}
you can see source code in Github.
Calling
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(entity: PostEntity): Flow<Long>
#Delete
fun deletePost(entity: PostEntity): Flow<Long>
returns compile error
Not sure how to handle insert method's return type.
public abstract kotlinx.coroutines.flow.Flow<java.util.List<java.lang.Long>> insertFlow(#org.jetbrains.annotations.NotNull()
Isn't possible to use Flow with Int or long to get ids for results of database operations like in RxJava?
#Insert(onConflict = REPLACE)
fun insert(entity: T): Maybe<Long>
#Insert(onConflict = REPLACE)
fun insert(entity: T): Single<Long>
As per the Async queries with Kotlin coroutines in Room, the equivalent for Maybe and Single in Kotlin coroutines is suspend:
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(entity: PostEntity): Long
#Delete
suspend fun deletePost(entity: PostEntity): Long
What is the best way to use coroutines with LiveData for selecting some data from database using Room.
This is My Dao class with suspended selection
#Dao
interface UserDao {
#Query("SELECT * from user_table WHERE id =:id")
suspend fun getUser(id: Long): User
}
Inside of View Model class I load user with viewModelScope.
Does it correct way to obtain user entity ?
fun load(userId: Long, block: (User?) -> Unit) = viewModelScope.launch {
block(dao.getUser(userId))
}
According developer android mentioned
val user: LiveData<User> = liveData {
val data = database.loadUser() // loadUser is a suspend function.
emit(data)
}
This chunk of code does not work
Your Room must return LiveData.
Use instead:
#Dao
interface UserDao {
#Query("SELECT * from user_table WHERE id =:id")
fun getUser(id: Long): LiveData<User>
}
I need your help please.
I have dao interface that save some configurations:
#Dao interface ConfigDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(config: Config)
#Update(onConflict = OnConflictStrategy.REPLACE)
fun update(config: Config)
#Query("select * from T_CONFIG where isSelected = :isSelected")
fun getConfig(isSelected: Boolean): Single<Config>
#Query("select * from t_config")
fun getConfigAll(): LiveData<MutableList<Config>>
#Query("update T_CONFIG set isSelected = :isSelected where idEnvironment = :id")
fun updateConfigById(id: String, isSelected: Boolean):Completable
#Transaction
fun updateConfigTransaction(configSelected: Config){
if (configSelected.idEnvironment == Environtment.Type.PRD.toString()){
updateConfigById(Environtment.Type.PRD.toString(), false)
updateConfigById(Environtment.Type.DEV.toString(), true)
}else{
updateConfigById(Environtment.Type.PRD.toString(), true)
updateConfigById(Environtment.Type.DEV.toString(), false)
}
}
}
I need to know when the transaction is complete with success or error.
I tried to implement Completable from io.reactivex but it's not possible.
Since Room 2.1.0
Additional Async Support: DAO methods annotated with #Insert, #Delete or #Update, along with #Query containing INSERT, DELETE or UPDATE statements, now support Rx return types Completable, Single, Maybe, and Guava's return type ListenableFuture, and they can also be suspend functions.
Source: https://developer.android.com/jetpack/androidx/releases/room#2.1.0
Older versions
Change the interface to an abstract class. You'll have to prefix all methods without implementation with abstract. Then:
abstract class ConfigDao(private val db: MyDatabase) {
private val scheduler = Schedulers.from(db.queryExecutor)
// Make sure the method is open so Room can generate the transaction handling code.
#Transaction
open fun updateConfigTransaction(configSelected: Config){
// ...
}
fun updateConfigTransactionAsync(configSelected: config): Completable {
return Completable
.fromAction { updateConfigTransaction(config) }
.subscribeOn(scheduler)
}
}
subscribeOn(db.queryExecutor) makes sure the query runs on the same thread as all other DAO methods returning RxJava types. Replace MyDatabase constructor parameter with whatever your database class is.
I have this database
interface UserDao {
#Insert(onConflict = REPLACE)
fun insert(user : User)
#Query("SELECT * FROM user")
fun get(): Flowable<List<User>>
#Query("DELETE FROM user")
fun deleteAll()
}
Everytime a record is inserted, get() will be triggered automatically, as expected.
override fun getUsers() : Flowable<User> {
return db.userDao().get()
}
How can I stop this from happening when deleteAll() is called?
You can use Single instead of Flowable. Secondly you can use a flag in your onNext() method of the subscriber. Turn the flag off after first run. Even if it gets triggered no changes will occur to your core code in onNext().