How to use suspend function on Room Db?
Asked Answered
H

7

8

I am using Room Db using coroutines in kotlin. This is my Dao interface:

@Dao
interface CheckListNameDao {

    @Insert
    suspend fun insertName(name: CheckListName)


    @Query("SELECT * FROM CheckListNamesTable")
    fun getAllNames(): LiveData<List<CheckListName>>
}

getAllNames() method works fine. The problem is with the insertName() method. When I remove the suspend keyword from the insertName() method, it throws this exception: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. But, when I use suspend keyword, I cannot build the project anymore. It shows the following error:

error: Methods annotated with @Insert can return either void, long, Long, long[], Long[] or List<Long>.
public abstract java.lang.Object insertName(@org.jetbrains.annotations.NotNull()

Why this error is showing? My code is based on this Android Room with a View - Kotlin

Edit: This is my repository:

class MainRepository(application: Application) {

        private var nameDao: CheckListNameDao = AppDatabase.getDatabase(application.applicationContext)
                .checkListNameDao()

        fun getAllNames(): LiveData<List<CheckListName>> {
            return nameDao.getAllNames()
        }

        suspend fun setNewListName(checkListName: CheckListName) {
            nameDao.insertName(checkListName)
        }
    }

This is the viewmodel:

class MainViewModel(application: Application) : AndroidViewModel(application) {

    private var mainRepository = MainRepository(application)

    fun getAllNames(): LiveData<List<CheckListName>> {
        return mainRepository.getAllNames()
    }

    fun setNewListName(name: String) {
        viewModelScope.launch {
            mainRepository.setNewListName(CheckListName(0, name))
        }
    }
}

EDIT 2:

I am also getting this error when I add the suspend keyword:

error: Type of the parameter must be a class annotated with @Entity or a collection/array of it.
kotlin.coroutines.Continuation<? super kotlin.Unit> p1);

This is the CheckListName data class:

@Entity(tableName = "CheckListNamesTable")
data class CheckListName(

        @PrimaryKey(autoGenerate = true)
        var id: Int,

        var name: String
)
Hardening answered 4/2, 2020 at 5:12 Comment(7)
Can you share the code from where you have call insertName method?Perkins
@KishanMaurya i have added repository and view model classesHardening
As per error, the insert should have a return type. @Insert suspend fun insertName(name: CheckListName):Long now handle this in viewmodelPerkins
@KishanMaurya I have added a Long return type and the error still shows up.Hardening
@KishanMaurya i have edited the question again.Hardening
share the code link. Let me debug from my end.Perkins
may we need to add conflict code like: @Insert(onConflict = OnConflictStrategy.REPLACE)Devisee
B
8

As per the Room Declaring Dependencies documentation, you need a dependency on room-ktx to use Coroutines and, with that, suspend methods:

implementation "androidx.room:room-ktx:2.2.3"
Balthasar answered 4/2, 2020 at 5:27 Comment(2)
What version of Room are you using?Balthasar
i am using version 2.2.3Hardening
U
5

Edit: Your code is correct it's can be used for room database with suspend function. Just edit your Gradle dependencies like bellow to fixed that error.

If you using kotlin version (1.7.0) shoud work with room latest alpha version (2.5.0-alpha02)

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0"

implementation "androidx.room:room-runtime:2.5.0-alpha02"
implementation "androidx.room:room-ktx:2.5.0-alpha02"
kapt "androidx.room:room-compiler:2.5.0-alpha02"

If you want using room in stable version (2.4.2) should work with kotlin version (1.6.20)

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20"

implementation "androidx.room:room-runtime:2.4.2"
implementation "androidx.room:room-ktx:2.4.2"
kapt "androidx.room:room-compiler:2.4.2"

I have tried both and they work. this is the reference: issue tracker

Unguentum answered 23/6, 2022 at 6:56 Comment(2)
This doesn't answers the question. The OP has asked how to use suspend function. But what you have written is the dependencies required for room database. Please edi it.Wentworth
Oh ya sorry, thank to remind me. I have edited my answer.Unguentum
M
1

The following code snippet contains a sample database configuration with one entity and one DAO:

@Entity
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val CheckListName: String?,
)
Mixologist answered 4/2, 2020 at 5:27 Comment(0)
M
0

The suspend does not work in Room DAO with the quires that return LiveData and with the higher Kotlin version than: 1.4.32

More please see here: Link

Macron answered 1/12, 2021 at 21:19 Comment(0)
M
0

For me changing from kapt to ksp worked, so, replace

kapt("androidx.room:room-compiler:2.5.2")

to

ksp("androidx.room:room-compiler:2.5.2")
Megganmeggi answered 18/10, 2023 at 12:57 Comment(0)
F
0

You should specify the context, so if you're calling from repository:

override suspend fun getProfiles(): List<Profile> = withContext(Dispatchers.IO) {
    profilesDao.getAll().map { it.toProfile() }
}

or calling from viewModel, remember viewModelScope runs on main thread:

viewModelScope.launch(Dispatchers.IO) {
   val profiles = profilesDao.getAll().map { it.toProfile() }
   // doSomething...
}
Filature answered 25/8, 2024 at 17:40 Comment(0)
U
-1

Only change to your fun to this :

@Insert(onConflict = OnConflictStrategy.REPLACE)

suspend fun insertName(name: CheckListName) : Long
Uund answered 11/10, 2020 at 12:9 Comment(1)
Please, check if the solution you offer has already been posted before posting.Steradian

© 2022 - 2025 — McMap. All rights reserved.