How to return newly inserted item(row) id using android room (Kotlin)?

Viewed 1817

I am using the similar solution to many similar topics, but still it doesn't want to work, and cant figure out why:

My Entity

@Entity(tableName = "single_item")
data class SingleItem (
    @PrimaryKey(autoGenerate = true)
    val id: Long? = 0L,
    val name: String,
    val icon: String,
    val price: Int)

DAO

@Insert
    suspend fun insertItem(item: SingleItem): Long

Repo

suspend fun insertItem(item: SingleItem): Long {
        return myDao.insertItem(item)
    }

Viewmodel

var insertedId = 0L
fun insertItem(item: SingleItem) = viewModelScope.launch {
        insertedId = myRepository.insertItem(item)
    }

Finally, call from Fragment

val newItem = SingleItem(null, "name","icon_name", 9999)
viewModel.insertItem(newItem)
Log.i("INSERT_ID", "Inserted ID is: ${viewModel.insertedId}")

And after i check the log, insertedId variable always returns 0. It doesn't change. What may be wrong?

1 Answers

Your insert method in the viewmodel is launching a new coroutine, it returns before it has executed the insert, so you get the initial value of 0. If you wait for the job to complete you will get the correct id.

Change it like this to see correct value:

var insertedId = 0L
fun insertItem(item: SingleItem) = viewModelScope.launch {
    insertedId = myRepository.insertItem(item)
    Log.i("INSERT_ID", "Inserted ID is: $insertedId")
}

If you want to get this value in your fragment you have to wait for the job to complete. The best way is to make your viewmodel insert method a suspend function instead of a fire and forget.

fun insertItem(item: SingleItem) = 
    myRepository.insertItem(item)

and in the fragment

lifecycleScope.launch {
    val id = viewModel.insertItem(item)
    Log.i("INSERT_ID", "Inserted ID is: $id")
}

but note that this is the wrong architecture, all business logic should be in the viewmodel, not the fragment.

Related