RealmResults没有在新的eventbus帖子上被销毁

时间:2017-05-13 17:41:20

标签: android realm greenrobot-eventbus

我试图使用GreenRobot在片段之间共享RealmResults。当用户点击某些按钮更改我想要显示的数据时,我调用invalidateRealmResult:

public void invalidateRealmResult() {
    RealmQuery<Climb> realmQuery =  mRealm.where(Climb.class);
    // other query modifiers added here....

    mResult = realmQuery.findAllSorted("date", Sort.ASCENDING);
    RealmChangeListener listener = new RealmChangeListener<RealmResults<Climb>>() {
            @Override
        public void onChange(RealmResults<Climb> element) {
            Log.d(TAG, "Realmresult onchange");
            EventBus.getDefault().postSticky(new RealmResultsEvent(mResult));
        }
    };
    mResult.addChangeListener(listener);
    EventBus.getDefault().postSticky(new RealmResultsEvent(mResult));
}

我的greenrobot活动如下:

public class RealmResultsEvent {
    public RealmResult mResult;

    public RealmResultsEvent(RealmResult result){
        this.mResult = result
    }
}

任何需要使用新结果更新的片段都会订阅该事件:

@Subscribe(sticky = true)
public void onRealmResultEvent(RealmResultsEvent event) {
    mResult = event.mResult;
    updateView();
}

@Override
public void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

我确保所有片段都在onStart()中订阅并在onStop()中取消订阅。

我的问题是,新的活动帖子似乎不会覆盖旧的RealmResults。我可以告诉RealmResults没有被销毁,因为每当我添加到领域数据库时,RealmChangeListener中的日志消息都会被调用越来越多,并且每隔一段时间UI就会显示错误的查询结果。

05-13 10:36:55.523 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.536 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.544 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.551 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.558 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.566 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.574 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.583 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.591 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.600 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.608 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange
05-13 10:36:55.616 17684-17684/com.example.grant.wearableclimbtracker D/MainActivity: Realmresult onchange

每当我做出改变时,它都会以一个交替的3,6,12,6,3 ...次来调用听众,重复这种模式。不确定这意味着什么,或者该信息是否有助于任何人。

2 个答案:

答案 0 :(得分:1)

根据问题中提供的示例代码段,很难说每次调用mResult之前为什么之前的invalidateRealmResult()没有获得GC。我同意你的评估,它似乎不是GC,因为听众仍在回应。我的猜测是,我们在这里缺少对mResult的额外参考。

一般领域使用:

观察样品的一个观察结果。目前尚不清楚,为什么每次将Climb结果添加到数据库时都需要重新运行查询。领域results are live,意味着如果与查询结果匹配的基础数据发生更改,则数据会自动更新。无需重新查询。添加更改侦听器,为您提供了一种订阅该事件(结果数据已更改)的方法,并在您的UI中做出反应。您可以通过将代码调整为以下内容来简化操作并避免此GC问题:

@Override
public void onStop() {
    super.onStop();
}

@Override
public void onStart() {
    super.onStart();
    mResult = fetchRealmResults()
}

public void fetchRealmResults() {
    RealmQuery<Climb> realmQuery =  mRealm.where(Climb.class);
    // other query modifiers added here....

    // Async suffix is optional here, but will push 
    // the work to a worker thread and then come back 
    // with the results on the main thread.
    mResult = realmQuery.findAllSortedAsync("date", Sort.ASCENDING);
    RealmChangeListener listener = new 
    RealmChangeListener<RealmResults<Climb>>() {
        @Override
        public void onChange(RealmResults<Climb> element) {
            // This will fire anytime there is a change 
            // to the underlying database that affects 
            // the results of this query.
            Log.d(TAG, "Realmresult onchange");
            updateView();
        }
    };
    mResult.addChangeListener(listener);
}

注意我为了简单起见拿出了GreenRobot的东西,但你可以继续使用它。我只会使用它来触发事件到您的片段,但不会发送更新的结果,因为您的片段已经在其现有的mResult引用中获得了更新的结果。有意义吗?

答案 1 :(得分:0)

我设法删除了大量代码,直到我缩小了问题范围。它与eventbus无关。出于某种原因,当我将realmresult重新分配给新的查询结果时,它不会垃圾收集旧的realmresult并且旧结果的changelisteners仍在触发。这创造了一个竞争条件,最后完成的任何一个听众都会出现在我的UI上。

我通过在重新分配字段之前移除侦听器来伪修复此问题:

public void invalidateRealmResult() { 
    RealmQuery<Climb> realmQuery =  mRealm.where(Climb.class);
    // other query modifiers added here.... 

    // ADDED THIS TO AVOID CALLING MULTIPLE LISTENERS
    if(mResult != null) {
        mResult.removeAllChangeListeners();
    }
    mResult = realmQuery.findAllSorted("date", Sort.ASCENDING);
    RealmChangeListener listener = new RealmChangeListener<RealmResults<Climb>>() {
        @Override 
        public void onChange(RealmResults<Climb> element) {
            Log.d(TAG, "Realmresult onchange");
            EventBus.getDefault().postSticky(new RealmResultsEvent(mResult)); 
        } 
    }; 
    mResult.addChangeListener(listener);
    EventBus.getDefault().postSticky(new RealmResultsEvent(mResult)); 
}

我称之为伪修复,因为它没有表现出奇怪的行为,但我很确定仍然存在不是GC的RealmResult对象,我不知道为什么。