领域返回陈旧的数据

我没有很多编写Android应用程序的经验。 为了好玩,我正在编写一个应用程序,将我的通话记录上传到我的服务器。 这整个应用程序是作为服务运行。 服务(在电话启动时开始)是注册ContentObserver的服务,然后调用我的自定义CallLog类。 我使用ContentObserver来侦听内容更改事件。 不幸的是,当我拨号时,ContentObserver被多次调用。

出于这个原因,我有一个函数,我称为markAsUploaded()成功上传后(我使用Retrofit markAsUploaded() 。 这个函数创建了一个名为CallLogUploaded (与我的常规CallLog模型不同)。 这个CallLogUploaded只有一个标识符,它是呼叫的dateTime时间,应该是足够独特的。 然后,当我遍历所有通话记录的列表时,我将检查每一个呼叫记录与一个isDataUploaded()函数,该函数执行一个Realm查询,并检查是否已经存在一个具有存储在数据库(领域)。 理论上,它应该工作。

但是,我注意到它并不总是工作。 我的数据看起来经常是陈旧的。 当我realm.isAutoRefresh() ,它返回false(虽然我发誓它返回一次)。 在我的isDataUploaded函数中,即使我在Realm上执行findAll() ,也没有看到所有的数据 – 但是数据肯定是碰到了markDataAsUploaded函数的。

这是我的代码 – 这是在Kotlin,但应该很容易理解:

  val callLogCall = service.sendCalLLogs(childId, dataToUpload) callLogCall.enqueue(object : Callback<Void> { override fun onResponse(call: Call<Void>, response: Response<Void>) { if (response.isSuccessful) { Log.i(AppConstants.LOG_TAG, "Call log data uploaded successfully!") this@CallLogData.markDataAsUploaded(dataToUpload) } else { Log.w(AppConstants.LOG_TAG, "Call log data upload failed") } } override fun onFailure(call: Call<Void>, t: Throwable) { Log.w(AppConstants.LOG_TAG, "Call log data upload error (onFailure) called") } }) // This function simply stores a Realm model for all the data that has been uploaded to the server private fun markDataAsUploaded(dataToUpload: List<CallLog>) { realm = Realm.getDefaultInstance() for (data in dataToUpload) { realm.beginTransaction() val callLogUploaded = realm.createObject(CallLogUploaded::class.java) callLogUploaded.callDate = data.callDate realm.commitTransaction() } } // This function checks to see if the data is already uploaded. private fun isDataUploaded(callLog: CallLog) : Boolean { return realm .where(CallLogUploaded::class.java) .equalTo("callDate", callLog.callDate) .count() > 0L } // Gets the call logs - not the entire function for (call in callLogs) { val callLog = CallLog() callLog.id = call.id callLog.callDate = Utilities.getTimestampAsSeconds(call.callDate) if (this.isDataUploaded(callLog)) { continue } callLog.name = call.name callLog.number = call.number } 

我对Realm非常陌生,对于Android开发来说也是一个相当新的东西,所以我希望你能给我提供任何帮助。 谢谢!

那是因为

 // This function simply stores a Realm model for all the data that has been uploaded to the server private fun markDataAsUploaded(dataToUpload: List<CallLog>) { realm = Realm.getDefaultInstance() for (data in dataToUpload) { realm.beginTransaction() val callLogUploaded = realm.createObject(CallLogUploaded::class.java) callLogUploaded.callDate = data.callDate realm.commitTransaction() } } 

这个方法有很多我以前写过的很多错误

  • Realm实例已打开,但从未关闭

  • 每个元素都有一个新的事务,而不是在一个事务中插入所有的元素

如果你不关闭Realm实例(每个实例都需要自己的close()调用),那么你的Realm实例永远不会更新,除非你实际上开始了一个事务并在事务内部做事。

你有三个解决方案:

1.)在事务内部的后台线程上执行你的逻辑,如果没有任何事情要做,那么取消事务 – 在事务中做的查询永远不会过时

2.)确保Realm实例关闭正确(虽然这在任何非自动化线程中都是必需的)

3.)hacky的解决方法是调用RealmRefresh.refreshRealm() getDefaultInstance() RealmRefresh.refreshRealm()之后的RealmRefresh.refreshRealm()根据我的回答堆栈溢出依赖于包私人API,但它的工作来解决这个问题


通常,您需要在线程的开头打开Realm实例,并在线程的末尾关闭该实例。

所以,它基本上是一个大的try(Realm realm = Realm.getDefaultInstance() { ... } onHandleIntent()


enqueue(new Callback() { @Override public void onSuccess(..) {...}在UI线程上运行,要在当前线程上运行它,应该使用call.execute()


代替

 for (data in dataToUpload) { realm.beginTransaction() val callLogUploaded = realm.createObject(CallLogUploaded::class.java) callLogUploaded.callDate = data.callDate realm.commitTransaction() } 

 realm.beginTransaction() for (data in dataToUpload) { val callLogUploaded = realm.createObject(CallLogUploaded::class.java) callLogUploaded.callDate = data.callDate } realm.commitTransaction() 

为了解版本保留,您可以阅读https://medium.com/@Zhuinden/understanding-realm-version-retention-and-synchronization-9a513c2445bb