情境
我有一个典型的UI线程和辅助线程方案.我做了一些工作,并将结果写到工作线程中的领域.结果是带有一些String字段的简单RealmObject.完成此操作后,我将UI线程上的事件发送到我的Activity(使用Otto事件总线)以报告工作已完成.
在我的活动中接收到事件后,我将查询结果,并且String字段未使用写入值进行更新.
在工作线程上:
// Did some work. Got some result
// Write to realm
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
MyResult result = realm.where(MyResult.class)
.equalTo("id", 1)
.findFirst();
result.someString = "hello world";
}
});
} finally {
if(realm != null){
realm.close();
realm = null;
}
}
//Post job done event on Otto bus
uiThreadBus.post(new JobDoneEvent());
活动中:
// Upon received JobDoneEvent
MyResult result = realm.where(MyResult.class)
.equalTo("id", 1)
.findFirst();
// result.someString is some stale value
Log.d("TAG", result.someString);
我做了什么
我意识到,如果我将查询包装在事务块中,那么当我尝试打印查询时,RealmObject将是最新的.
// Upon received JobDoneEvent
MyResult result = null;
try{
realm.beginTransaction();
result = realm.where(MyResult.class)
.equalTo("id", 1)
.findFirst();
realm.cancelTransaction();
}
catch(Exception e) {
realm.cancelTransaction();
}
// result.someString is up-to-date
Log.d("TAG", result.someString);
问题
>获取最新RealmObject的正确方法是什么?我是否每次都必须将它们放入事务块中以强制其与工作线程“同步”?有没有可以遵循的模式?
>开始领域交易(通过Realm#beginTransaction()或Realm#executeTransaction())究竟是做什么的?它是否阻止其他线程进行读/写尝试?在事务中执行长时间操作(例如网络请求)是否有任何危害?
编辑
实际代码:
// Did some work. Got some result
// Write to realm
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
User managedUser = result.payload.createOrUpdateInRealm(realm,
MyApplication.getPrimaryKeyFactory());
Log.i("TAG", "updated user: " + managedUser.getId());
}
});
} finally {
if(realm != null) {
realm.close();
realm = null;
}
}
//Post job done event on Otto bus
MyApplication.getBusInstance().post(new LoginEvent());
// Writing to realm method
public User createOrUpdateInRealm(@NonNull Realm realm,
@NonNull PrimaryKeyFactory pkFactory) {
User managedUser = realm.where(User.class)
.equalTo("primary_key", pk)
.findFirst();
managedUser.setId(xUserId);
return managedUser;
}
// Event receiving method in Activity
@Subscribe
public void loginEventReceived(LoginEvent event) {
User user = mRealm.where(User.class)
.equalTo("primary_key", mPk)
.findFirst();
Log.d("TAG", user.getId());
}
解决方法:
领域使用特殊的“侦听器”线程与其他线程通信,该线程将消息放入UI线程Looper队列中.我们不会提供任何保证,因为多种原因可能会延迟.奥托(Otto)将直接发送一条消息,这很可能会在回圈消息到达之前发生.在这种情况下,UI线程上的数据将显示为“陈旧”.
对于这些类型的通知,最好使用Realm更改侦听器.在这种情况下,数据准备就绪时会通知您.
另请参阅:https://github.com/realm/realm-java/issues/3427