【问题标题】:Wait for data update in realm-java between threads在线程之间等待realm-java中的数据更新
【发布时间】:2016-11-21 10:54:54
【问题描述】:

我在等待工作线程上的新数据时遇到问题。数据对象被复制到主线程上的领域,但几乎在之后我需要从工作线程访问这个对象,然后报告说领域中现在不存在这样的对象(它新打开的领域实例)。我记得有一个方法 load() 会阻止执行到下一次更新,但它在较新的版本中被删除了。而且我不能为此使用更改通知,因为这不是 Looper 线程..

我现在能想到的唯一方法是让线程休眠一段神奇的时间,并向上帝祈祷它已经更新,但恕我直言,这种方法非常不确定。

任何人都可以在这里提供建议,我如何确保我阅读当时最新的数据?

【问题讨论】:

  • 在工作线程上为每个工作单元打开和关闭你的领域应该可以解决问题。如果您看到旧数据,那是因为您的 Realm 上次没有正确关闭。
  • 是的,我认为情况正是如此。我忘了关闭实例,这很奇怪,因为这是一个请求拦截器,所以我没有用完内存,所以创建了实例非常迅速...

标签: java android multithreading realm


【解决方案1】:

一种可能的技巧是创建一个您在最后取消的交易。

realm.beginTransaction(); // blocks while there are other transactions
... // you always see the latest version of the Realm here
realm.cancelTransaction();

如果线程在 UI 线程将对象保存到领域后启动,则此方法有效。

您也可以尝试以下解决方法:https://stackoverflow.com/a/38839808/2413303(虽然它对等待并没有真正的帮助)

【讨论】:

  • (但是,您应该始终在后台线程上关闭 finally { 中的 Realm 实例)
【解决方案2】:

尝试使用QueryListener,它是当更新对象时触发,满足某些条件更新

【讨论】:

  • 究竟如何设置QueryListener?我在文档或 RealmQuery 对象方法中找不到任何内容。这是否与在 RealmResults 或 RealmObject 上设置的常规更改通知有所不同,如果是,它们是否在非 Looper 线程上提供?
  • 监听器在非循环线程上不起作用。如果您确定某些事情发生了变化,您可以使用realm.waitForChange()。但是,您的第一条语句表明您没有像您希望的那样控制您的事件,就好像在 UI 线程上发生了写入一样,如果在 UI 线程上写入之后启动该线程,那么后台线程将 100% 可用。
  • @AlexShutov 因为我无法控制库创建的线程...
  • @ChristianMelchior 是的,工作线程来自 Rx 库......更具体地说,它们由 io 调度程序返回,我相信它保留了一个线程池..
【解决方案3】:

使用 realm.beginTransaction() 和 realm.commitTransaction() 而不是 realm.executeTransaction(Realm.Transaction)

问题在于 executeTransaction() 会自动处理调用 realm.cancelTransaction() 以防万一抛出异常,而另一种选择通常忽略 try-catch。

是的,您应该对最终不会提交的事务调用 cancel

例如,在后台线程上:

    // SAY NO TO THIS
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction(); // NO
realm.copyToRealm(dog)
realm.commitTransaction(); // NO NO NO NO NO
    // YOU NEED TO CLOSE THE REALM

// ----------------------

// SAY YES TO THIS
Realm realm = null;
try { // I could use try-with-resources here
    realm = Realm.getDefaultInstance();
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.insertOrUpdate(dog);
        }
    });
} finally {
  if(realm != null) {
    realm.close();
  }
}

// OR IN SHORT (Retrolambda)

try(Realm realmInstance = Realm.getDefaultInstance()) {
    realmInstance.executeTransaction((realm) -> realm.insertOrUpdate(dog));
}

这样做的问题是,在后台线程上,拥有一个即使线程执行结束也不会关闭的打开 Realm 实例非常昂贵,并且可能导致奇怪的错误。因此,建议在 finally 块中执行时关闭后台线程上的 Realm。这包括 IntentServices。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-21
    • 2012-07-05
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多