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>
}
Related
How is possible to add multiple databases in room using ViewModel class? Do I need a different ViewModel class and a different #Entity and a different #Dao for each database, or can I use the same #Entity and #Dao of another database, sorry if the question is pretty obvious, thanks a lot in advance
I tried different Databases with the same #Entity, #Dao and ViewModel, Didn't work
I also tried Different everything, the database appeared but i couldn't query it, please help :(
Yes, you will need a separate Entity class, and Dao class for each database in Room. This is because each database will have its own set of data, and the Entity and Dao classes are used to define the schema and provide access to the data in the database.
// Define the Entity class for each database
#Entity(tableName = "data1")
data class Data1(
#PrimaryKey(autoGenerate = true) val id: Int,
val data: String
)
#Entity(tableName = "data2")
data class Data2(
#PrimaryKey(autoGenerate = true) val id: Int,
val data: String
)
// Define the Dao class for each database
#Dao
interface Data1Dao {
#Query("SELECT * FROM data1")
fun getAll(): List<Data1>
#Insert
fun insert(data: Data1)
// Other database operations...
}
#Dao
interface Data2Dao {
#Query("SELECT * FROM data2")
fun getAll(): List<Data2>
#Insert
fun insert(data: Data2)
// Other database operations...
}
// Define the ViewModel class for each database
class MyViewModel1: ViewModel() {
val db1: Database1
val db2: Database2
init {
db1 = Room.databaseBuilder(context, Database1::class.java,
"db1").build()
db2 = Room.databaseBuilder(context, Database2::class.java,
"db2").build()
}
fun getDataFromDb1(): List<Data1> {
return db1.data1Dao().getAll()
}
fun getDataFromDb2(): List<Data2> {
return db2.data2Dao().getAll()
}
// Other database operations...
}
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.
I have Room database interface which is a Kotlin file and as I dont want the calls to run on mainthread I am using kotlin Suspend. how can I use suspend function from java
I have two method where I want to insert a User and another to retrieve the users
these are the errors I get in my java file
Code
Room Dao interface
UserDao
#Dao
interface UserDao {
fun getAllUsersAsync(): CompletableFuture<List<User>> =
GlobalScope.future { getAllUsers() }
#Query("SELECT * FROM user")
suspend fun getAllUsers(): List<User>
#Insert
suspend fun insertUser(user: User): Long
}
Java code
private Long addUser(com.i6systems.in2plane.AppDatabase.User user) {
return userDao.insertUser(user);
}
private List<com.i6systems.in2plane.AppDatabase.User> getUsers () {
return userDao.getAllUsersAsync();
}
your help is much appreciated
Thanks
R
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)
}
}
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.