user3806331 user3806331 - 3 months ago 86
Android Question

Android Kotlin Realm Proper Way to Query+Update Async

I recently faced a problem in which i had in memory a RealResult List of objects and was showing it in a view. Upon user click, the current showing item should be marked as deleted in realm (property

isDeleted
)

So i was just getting that object from the lazy
RealmResults
list, open a transaction and mark it deleted. As the RealmResults are auto-updated, i had a change listener bound to a
notifityDataSetChanged
. Everything works fine except this warning:

Mixing asynchronous queries with local writes should be avoided. Realm will convert any async queries to synchronous in order to remain consistent. Use asynchronous writes instead


Which is problematic because my list is enormous and i don't want the query to become
sync
. I solved it this way, which i don't know it it is right. Instead of giving the item object to the update function, i give the id of the object, and then do this:

Realm.getDefaultInstance().use { realm ->

realm.executeTransactionAsync {
// find the item
realm.where(ItemRealm::class.java)
.equalTo(ItemRealm.ID, itemId).findFirstAsync()
.addChangeListener(object : RealmChangeListener<ItemRealm> {
override fun onChange(element: ItemRealm) {
element.deleted = true
element.removeChangeListener(this)
}
})
}
}


The problem which im unsure is the
async
part of the query inside an async transaction.

Edit. Actually, it throws
java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.


Edit2: Tried this and show Realm access on different thread:

fun setItemDeleted(itemId: Long) {
// write so new realm instance
Realm.getDefaultInstance().use { realm ->
realm.executeTransactionAsync {
// find the item
val item = realm.where(ItemRealm::class.java)
.equalTo(ItemRealm.TIMESTAMP, itemId).findFirst()
item?.userDeleted = true
}
}
}

Answer

Everything in executeTransactionAsync() runs on a background thread, so you should use the synchronous methods to obtain your object inside it.

Realm.getDefaultInstance().use { realm ->
    realm.executeTransactionAsync { bgRealm ->
        // find the item
        val item = bgRealm.where(ItemRealm::class.java)
                        .equalTo(ItemRealm.ID, itemId).findFirst()
        item?.deleted = true
    }
}
Comments