Search code examples
androidandroid-roomandroid-architecture-components

Room get id from execute method


I have a fragment with a RecyclerView and FloatingActionButton. Pressing the fab opens a dialog with the settings for the new item. By clicking on the positive button, I insert a new element into the database, doing the following steps:

1) Call from dialog

viewModel.createItem()

2) In the ViewModel

fun createItem() {
    return repository.insertItem(Item("${name.value}"))
}

3) Repository looks like

@Singleton
class Repository @Inject constructor(
    private val appExecutors: AppExecutors,
    private val itemDao: ItemDao
) {

    fun insertItem(item: Item) {
        appExecutors.diskIO().execute{ itemDao.insert(item) }
    }

    fun loadItemList() = itemDao.getItemList()
}

4) Dao

@Dao
interface ItemDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(item: Item) : Long

    @Query("SELECT * FROM item ORDER BY name")
    fun getItemList() : LiveData<List<Item>>
}

5) Item

@Entity (tableName = "item")
data class Item(
        @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "_id") val id: Long,
        @ColumnInfo(name = "name") val name: String
) {
    @Ignore
    constructor(name: String) : this(0, name)
}

And then I want to navigate to the detail fragment for the inserted item. So i need the id of this item, which is returned by Room. But how can I return id from execute method in the repository? Or maybe you know another way to do this.

P.s. I use Dagger and all of the Architecture Components libraries.


Solution

  • itemDao.insert(item) already returns the id of the new element. What you need to do now is to send this id back to your frontend (or whereever you want to use the new id) via a callback.

    You could create a listener:

    interface ItemInsertedListener {
        fun onItemInserted(itemId: Long)
    }
    

    Add the interface as optional argument for your insertItem method:

    fun insertItem(item: Item, callback: ItemInsertedListener?) {
        appExecutors.diskIO().execute {
            val id = itemDao.insert(item)
            callback?.onItemInserted(id)
        }
    }
    

    And finally pass the ItemInsertedListener to your repo in your createItem method. When the callback returns you can redirect the user to the Fragment, given that the activity is still visible. Also bear in mind that the callback might run on a different thread, so explicitly switch to the UI thread before making UI changes.