为什么 Realm 找不到我之前插入事务中的对象?
Why Realm doesn't find object which I inserted in transaction before?
我正在尝试在 Clean Architecture 中的 Web 套接字上实现一个简单的聊天应用程序。我不得不选择一个数据库来缓存所有信息,所以我决定使用 Realm,因为我听说它对于任何类型的移动应用程序来说都是非常好的数据库。但是当我真正面对Realm时,用它来实现缓存逻辑对我来说是一个非常痛苦的经历。
所有问题都来自将事务应用到数据库,然后必须在使用 Realm 的所有线程上同步该数据库。我的代码似乎存在某种同步问题。比如我想把我的对象保存到Realm中,然后从里面查询出来。
这里我有两个简单的功能来保存和聊天:
fun getBackgroundLooper(): Looper {
val handlerThread = HandlerThread("backgroundThread")
if (!handlerThread.isAlive)
handlerThread.start()
return handlerThread.looper
}
fun saveChat(chat: Chat): Completable {
val realmChat = ChatMapper.domainToCache(chat)
return Completable.create { e ->
val realm = Realm.getDefaultInstance()
realm.executeTransactionAsync({
it.insertOrUpdate(realmChat)
}, {
realm.close()
e.onComplete()
}, {
realm.close()
e.onError(it)
})
// Subscribe on background looper thread
// to be able to execute async transaction
}.subscribeOn(AndroidSchedulers.from(getBackgroundLooper()))
}
fun getSingleChat(chatId: String): Single<Chat> {
return Single.defer {
val realm = Realm.getDefaultInstance()
realm.isAutoRefresh = true
val realmChat = realm.where(RealmChat::class.java)
.equalTo("id", chatId).findFirstAsync()
if (realmChat.isValid) {
realmChat.load()
val chat = ChatMapper.cacheToDomain(realmChat)
realm.close()
Single.just(chat)
}
realm.close()
Single.error<Chat>(ChatNotExistException())
// Subscribe on background looper thread
// to be able to execute auto refreshing
}.subscribeOn(AndroidSchedulers.from(getBackgroundLooper()))
}
所以,当我尝试 运行 像这样的简单代码时
remote.getChat().flatMap {
cache.saveChat(it) //save chat to realm
.andThen(cache.getSingleChat(it.id)) //then query it by id
}
不管是什么,我总是得到 ChatNotExistException
,但是如果我再次尝试 运行 查询或在重新启动应用程序后再次查询,则会找到聊天对象
我也尝试了很多不同的方法来执行这段代码:
我尝试在getSingleChat
中使用realm.refresh()
或者根本不使用它。
我尝试使用 findFirst()
和 findAll()
而不是 findFirstAsync()
同步查询聊天。
我尝试在没有 .subscribeOn()
的情况下查询当前线程上的聊天。
我尝试使用 realm.executeTransaction()
而不是异步事务。
我尝试在保存和查询之间添加线程休眠,这样事务可能需要一些时间才能应用,我需要等待才能尝试查询聊天
我恳求任何人向我解释我做错了什么以及如何使此代码正常工作。我无法更改我的应用程序的体系结构并使用 Realm 对象作为我的视图模型,我需要在这些情况下找到解决方案。
But when I actually faced the Realm, it turned out to be really painful experience for me to implement caching logic with it.
阅读有关最佳实践的文档会有所帮助。例如,默认的想法是在 UI 线程上使用异步查询定义一个 RealmResults,向其添加一个更改侦听器,并观察数据库的最新发射。
除了保存到数据库和观察数据库之外,没有涉及“缓存”。任何额外的复杂性都是由您添加的,完全是可选的。
All problems come from applying transaction to database which then must be synced on all threads working with Realm.
所有循环线程自动使 Realm 自动刷新,因此如果 addChangeListener
按文档中的预期使用,则无需欺骗,Realm 将管理线程之间的同步。
I want to save my object to Realm and then query it out of.
realm.executeTransactionAsync({
当您已经在后台线程时,没有理由使用 executeTransactionAsync
。
try(Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction((r) -> {
// do write here
});
}
realm.where(RealmChat::class.java)
如果你import io.realm.kotlin.where
,那么你可以realm.where<RealmChat>()
。
.findFirstAsync()
当您已经在后台线程中时,没有理由使用 findFirstAsync()
而不是 findFirst()
。当你在后台线程时也没有理由使用 load()
,因为无论如何你应该首先使用 findFirst()
。
您也很可能缺少 return@defer Single.just(chat)
以实际 return 聊天(如果找到的话)。这很可能是您原来的问题所在。
虽然您正在处理处理程序线程,但您可能需要考虑查看 this project called "Monarchy",因为它打算在后台循环程序上设置 运行 查询的能力线程,同时仍然观察结果。它被标记为 stagnant
但想法是正确的。
我正在尝试在 Clean Architecture 中的 Web 套接字上实现一个简单的聊天应用程序。我不得不选择一个数据库来缓存所有信息,所以我决定使用 Realm,因为我听说它对于任何类型的移动应用程序来说都是非常好的数据库。但是当我真正面对Realm时,用它来实现缓存逻辑对我来说是一个非常痛苦的经历。
所有问题都来自将事务应用到数据库,然后必须在使用 Realm 的所有线程上同步该数据库。我的代码似乎存在某种同步问题。比如我想把我的对象保存到Realm中,然后从里面查询出来。
这里我有两个简单的功能来保存和聊天:
fun getBackgroundLooper(): Looper {
val handlerThread = HandlerThread("backgroundThread")
if (!handlerThread.isAlive)
handlerThread.start()
return handlerThread.looper
}
fun saveChat(chat: Chat): Completable {
val realmChat = ChatMapper.domainToCache(chat)
return Completable.create { e ->
val realm = Realm.getDefaultInstance()
realm.executeTransactionAsync({
it.insertOrUpdate(realmChat)
}, {
realm.close()
e.onComplete()
}, {
realm.close()
e.onError(it)
})
// Subscribe on background looper thread
// to be able to execute async transaction
}.subscribeOn(AndroidSchedulers.from(getBackgroundLooper()))
}
fun getSingleChat(chatId: String): Single<Chat> {
return Single.defer {
val realm = Realm.getDefaultInstance()
realm.isAutoRefresh = true
val realmChat = realm.where(RealmChat::class.java)
.equalTo("id", chatId).findFirstAsync()
if (realmChat.isValid) {
realmChat.load()
val chat = ChatMapper.cacheToDomain(realmChat)
realm.close()
Single.just(chat)
}
realm.close()
Single.error<Chat>(ChatNotExistException())
// Subscribe on background looper thread
// to be able to execute auto refreshing
}.subscribeOn(AndroidSchedulers.from(getBackgroundLooper()))
}
所以,当我尝试 运行 像这样的简单代码时
remote.getChat().flatMap {
cache.saveChat(it) //save chat to realm
.andThen(cache.getSingleChat(it.id)) //then query it by id
}
不管是什么,我总是得到 ChatNotExistException
,但是如果我再次尝试 运行 查询或在重新启动应用程序后再次查询,则会找到聊天对象
我也尝试了很多不同的方法来执行这段代码:
我尝试在
getSingleChat
中使用realm.refresh()
或者根本不使用它。我尝试使用
findFirst()
和findAll()
而不是findFirstAsync()
同步查询聊天。我尝试在没有
.subscribeOn()
的情况下查询当前线程上的聊天。我尝试使用
realm.executeTransaction()
而不是异步事务。我尝试在保存和查询之间添加线程休眠,这样事务可能需要一些时间才能应用,我需要等待才能尝试查询聊天
我恳求任何人向我解释我做错了什么以及如何使此代码正常工作。我无法更改我的应用程序的体系结构并使用 Realm 对象作为我的视图模型,我需要在这些情况下找到解决方案。
But when I actually faced the Realm, it turned out to be really painful experience for me to implement caching logic with it.
阅读有关最佳实践的文档会有所帮助。例如,默认的想法是在 UI 线程上使用异步查询定义一个 RealmResults,向其添加一个更改侦听器,并观察数据库的最新发射。
除了保存到数据库和观察数据库之外,没有涉及“缓存”。任何额外的复杂性都是由您添加的,完全是可选的。
All problems come from applying transaction to database which then must be synced on all threads working with Realm.
所有循环线程自动使 Realm 自动刷新,因此如果 addChangeListener
按文档中的预期使用,则无需欺骗,Realm 将管理线程之间的同步。
I want to save my object to Realm and then query it out of.
realm.executeTransactionAsync({
当您已经在后台线程时,没有理由使用 executeTransactionAsync
。
try(Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction((r) -> {
// do write here
});
}
realm.where(RealmChat::class.java)
如果你import io.realm.kotlin.where
,那么你可以realm.where<RealmChat>()
。
.findFirstAsync()
当您已经在后台线程中时,没有理由使用 findFirstAsync()
而不是 findFirst()
。当你在后台线程时也没有理由使用 load()
,因为无论如何你应该首先使用 findFirst()
。
您也很可能缺少 return@defer Single.just(chat)
以实际 return 聊天(如果找到的话)。这很可能是您原来的问题所在。
虽然您正在处理处理程序线程,但您可能需要考虑查看 this project called "Monarchy",因为它打算在后台循环程序上设置 运行 查询的能力线程,同时仍然观察结果。它被标记为 stagnant
但想法是正确的。