DAO when to use suspend function android - android

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.

Related

Is it possible to use Flow with Room delete or insert operations as it's used in RxJava with Single or Maybe that returns row ids?

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

Select single column value as livedata

As the title indicates I'm trying to select a single column from my database as livedata. But I'm getting the following error message.
error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.lang.Float>)
I'm tracking the phones location and insert location objects into a table called LocationEntity.
My entity looks as the following
data class LocationEntity(
...
val speed: Float,
...
#PrimaryKey(autoGenerate = true) val id: Long = 0
)
My DAO looks as the following
private const val ACCURACY_THRESHOLD = 50
private const val speedSql = """
SELECT speed
FROM LocationEntity
WHERE runId = :runId AND accuracy < $ACCURACY_THRESHOLD
ORDER BY dateTime
DESC LIMIT 1
"""
#Dao
interface LocationDao {
...
#Query(speedSql)
suspend fun speed(runId: Long): LiveData<Float>
}
Any clue about what I'm doing wrong?
suspend and LiveData doesn't work together. The below works.
#Dao
interface LocationDao {
...
#Query(speedSql)
fun speed(runId: Long): LiveData<Float>
}
Actually I think LiveData works out of the box, there's no reason to use Coroutines when returning LiveData.
When using LiveData it already handles it on a background thread. When NOT using LiveData then in that case you can use Coroutines (and maybe eventually Coroutines Channels) or RxJava etc.
You may find something about insert data by using livedata in google codelab
The most interesting part is the code below
#Dao
interface WordDao {
#Query("SELECT * from word_table ORDER BY word ASC")
fun getAllWords(): LiveData<List<Word>>
#Insert
suspend fun insert(word: Word)
#Query("DELETE FROM word_table")
fun deleteAll()
}
class WordRepository(private val wordDao: WordDao) {
val allWords: LiveData<List<Word>> = wordDao.getAllWords()
#WorkerThread
suspend fun insert(word: Word) {
wordDao.insert(word)
}
}

Room #Transaction and Rx Completable

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.

Obtain entity using coroutines api

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>
}

How return completable on room transaction Android

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.

Categories

Resources