如何在Realm异步事务执行完成后返回值?
解决Realm异步事务无法返回结果的问题
这个问题我太熟了——Realm的异步操作天生就没法直接返回值,因为executeTransactionAsync是在后台线程执行的,你的getConversations方法会在异步事务启动后立刻结束返回,此时结果还完全没准备好呢!而且你代码里定义的conversations变量,内部局部变量和外部的根本不是同一个,外部的永远拿不到异步查询的结果。
下面给你两个实用的解决方案:
方案一:自定义回调接口(最通用)
既然异步操作不能同步返回,那就用回调来接收结果,这是异步编程的标准做法。
第一步:定义回调接口
先写一个接口来处理成功和失败的情况:
public interface OnConversationsLoadedListener { void onConversationsLoaded(List<Group> conversations); void onLoadFailed(Exception error); }
第二步:修改getConversations方法
把方法改成接收回调参数,在异步事务完成后通过回调传递结果:
public void getConversations(final OnConversationsLoadedListener listener) { try { mRealm = Realm.getDefaultInstance(); mRealm.executeTransactionAsync( // 后台执行的事务逻辑 new Realm.Transaction() { @Override public void execute(Realm realm) { // 在这里执行查询 RealmResults<Group> results = realm.where(Group.class) .findAllSorted("time", Sort.DESCENDING); // 注意:RealmResults是线程绑定的,必须拷贝成普通List才能跨线程传递 List<Group> conversations = realm.copyFromRealm(results); // 通过回调传递结果 if(listener != null) { listener.onConversationsLoaded(conversations); } } }, // 事务成功的回调(可选,这里可以留空,因为我们已经在execute里传结果了) new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // 可以在这里做一些事务完成后的清理工作 } }, // 事务失败的回调 new Realm.Transaction.OnError() { @Override public void onError(Throwable error) { if(listener != null) { listener.onLoadFailed(new Exception(error)); } } } ); } catch (Exception e) { if(listener != null) { listener.onLoadFailed(e); } } }
第三步:调用方法
在需要获取对话列表的地方,传入回调实现:
getConversations(new OnConversationsLoadedListener() { @Override public void onConversationsLoaded(List<Group> conversations) { // 在这里拿到结果,比如更新UI、处理业务逻辑 updateConversationUI(conversations); } @Override public void onLoadFailed(Exception error) { // 处理查询失败的情况,比如弹提示 Toast.makeText(context, "加载对话失败:" + error.getMessage(), Toast.LENGTH_SHORT).show(); } });
方案二:用Realm异步查询(更简洁,适合纯查询场景)
如果你只是做查询操作,不需要修改数据,那根本不需要用事务!直接用Realm的异步查询方法findAllSortedAsync更高效:
public void getConversations(final OnConversationsLoadedListener listener) { try { mRealm = Realm.getDefaultInstance(); // 发起异步查询 RealmResults<Group> results = mRealm.where(Group.class) .findAllSortedAsync("time", Sort.DESCENDING); // 添加结果监听 results.addChangeListener(new RealmChangeListener<RealmResults<Group>>() { @Override public void onChange(RealmResults<Group> results) { // 确认结果已加载完成 if(results.isLoaded() && !results.isInvalidated()) { List<Group> conversations = mRealm.copyFromRealm(results); listener.onConversationsLoaded(conversations); // 不需要继续监听的话,移除监听器并关闭Realm实例 results.removeChangeListener(this); mRealm.close(); } } }); } catch (Exception e) { listener.onLoadFailed(e); if(mRealm != null && !mRealm.isClosed()) { mRealm.close(); } } }
关键注意点
- 线程绑定规则:Realm的
RealmResults、RealmObject都是线程绑定的,不能直接跨线程传递,必须用copyFromRealm拷贝成普通Java对象才能在其他线程(比如UI线程)使用。 - Realm实例生命周期:异步操作会持有Realm实例,不要在方法里直接调用
mRealm.close(),否则会导致异步操作报错,应该在回调完成后再关闭(方案二里的做法),或者让Realm自动管理(方案一的executeTransactionAsync会自动处理实例生命周期)。
内容的提问来源于stack exchange,提问作者SonVi
相关产品推荐
相关产品推荐

