【问题标题】:Realm data sync not consistent领域数据同步不一致
【发布时间】:2016-08-25 06:26:24
【问题描述】:

我遇到了一个问题,每次我执行相同的查询时,Realm 有时都会返回不同的数据。目前我正在使用 SyncAdapter 进行上传。这个想法是我们正在尝试实现离线模式。

因此,当用户创建一个项目时,它会被添加到 Realm 数据库中。我通过获取 maxId 并向其添加 1000 手动生成该项目的 ID。之后,我将 itemID 发送到 UploadSyncAdapter,在那里我获取 itemById 并将其发送到后端,后端返回具有真实 ID 的项目。所以在那之后我删除了旧项目并将新项目插入到 Realm 中。

在我返回并读取数据后,它每秒返回一次,例如一个大小为 115 的数据数组,另一次是一个大小为 116 的数组。我什至通过 ID 使用调试器搜索项目,它真的找到了一次该项目,第二次没有。但看起来在我重建项目之后,该项目就在那里并且它可以正常工作,或者如果我使用 Instant Run 重新运行应用程序。

任何帮助表示赞赏...

更新 顺便说一句,我正在使用 RXjava 从服务器获取数据,但它正在当前线程(SyncAdapter 线程)上被订阅和观察。

代码如下:

@Override
public void onNext(TaskResponse taskResponse) {
     tasksDatabaseManager.deleteTaskById(taskId);
     List<Task> tasks = taskResponse.getTaskDataList();
     tasksDatabaseManager.insertTasks(tasks);
 }

public void deleteTaskById(int taskId){
    Realm realm = Realm.getDefaultInstance();
    realm.beginTransaction();
    RealmResults<Task> rows = realm.where(Task.class).equalTo(ID, taskId).findAll();
    rows.deleteAllFromRealm();
    realm.commitTransaction();
    realm.close();
}

private void copyOrUpdateTasks(List<Task> tasksList){
    Realm realm = Realm.getDefaultInstance();
    ArrayList<Task> updatedTaskList;
    //first initialize task permissions
    updatedTaskList = filterTasksByPermission(tasksList);
    //initialize custom task data
    for (Task task : updatedTaskList) {
        initializeTaskCustomFields(task);
    }
    //save new data
    Log.d(TAG, "tasks number before update: " + getTasks().size());
    realm.beginTransaction();
    realm.copyToRealmOrUpdate(updatedTaskList);
    realm.commitTransaction();
    realm.close();

    Log.d(TAG, "tasks number after update: " + getTasks().size());
}

在 filterTasksByPermission 中,我只是计算了任务的一些权限,但任务正在列表中返回。在 initializeTaskCustomFields 中,我也只是在保存到 Realm 之前计算对象的 2 个字段(这样我也将这些值保存在 Realm 中)

【问题讨论】:

  • 我需要查看您在哪里执行删除和插入新元素的事务代码才能给出正确的答案。我的猜测是您在后台线程上使用了多个事务,而不是评估查询以获取事务中的元素。此外,请确保在完成操作后关闭后台线程(即同步适配器的线程)上的 Realm,然后重新打开 Realm 实例以进行下一个操作。
  • 哦,看,我是对的:多个事务并执行查询以确定事务之外的写入参数(尽管很高兴看到 filterTasksByPermission 的代码)跨度>
  • 另外,您应该考虑将realm.close() 放入finally {
  • 事实上,在 filterTasksByPermission 中,我也有打开事务并关闭它的情况。但是,如果我有多个事务,如果我每次都提交它们并关闭 Realm,为什么这很重要?
  • 因为它是一个非循环线程,因此不会更新它的 Realm 实例。虽然如果您在事务内部而不是在事务外部进行查询,您仍然应该能够看到最新数据。

标签: android database synchronization realm


【解决方案1】:

经过一番研究,我发现了问题所在。但是,如果我错了,请纠正我。我在我的 Rx 调用中用 Subscribers.newThread() 替换了我的 Subscribers.io(),现在它工作正常。所以我的理论是:

在调用我的 UploadAdapter 以上传更改的数据之前,我正在使用带有 Subscribers.io() 的 Rx 调用将我的项目插入数据库中。 Subscribers.io() 使用线程池来重用线程,或者在必要时创建新线程。因此,假设它产生了一个名为“A”的线程。线程 A 获取一个 Realm 实例(假设 Realm 快照为“1”)并将创建的项目插入其中。在调用 SyncAdapter 之后,它还会获得一个具有相同 Realm 快照“1”的新 Realm 实例。 SyncAdapter 完成将数据上传到服务器后,它会删除旧项目,并插入从服务器获取的新项目。因此,在此 Realm 数据更改后,最新的 Realm 快照现在为“2”。 SyncAdapter 向 Activity 发送一个上传完成的广播,它应该从 Realm 数据库中获取新数据。

为了从 Realm 读取数据,我还使用带有 Subscribers.io() 的 Rx。因此,当从 Realm 请求新数据时,Subscribers.io() 的池中已经有一个线程等待重用,这就是线程“A”。由于这个线程是一个非 Looper 线程,它不知道 Realm 数据发生了变化,它仍然使用 Realm 快照“1”,所以这就是我从 Realm 获取旧数据的原因。在刷新几次之后,Subscribers.io() 可能会创建一个新线程,比如说线程“B”。

所以线程“B”也得到了一个Realm快照,这次是最新的快照,所以快照“2”。它会返回正确的数据。

因此,当使用 Subscribers.newThread() 时,它总是会创建一个新线程,并且总是拥有最新的 Realm 快照。

这里是关于 Subscribers.io() 和 Subscribers.newThread() 之间区别的链接: Retrofit with Rxjava Schedulers.newThread() vs Schedulers.io()

希望这对某人有所帮助!

【讨论】:

  • 不错的发现。这是有道理的。
  • 感谢分享。帮了我很多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多