【问题标题】:RxJava + Retrofit + Realm is doing unlimited get requestRxJava + Retrofit + Realm 正在做无限的获取请求
【发布时间】:2017-07-17 04:54:03
【问题描述】:

我对 rxJava 完全陌生,这真的很令人困惑,我想先让我的应用程序离线,我决定使用 Realm 和 Retrofit,首先我想从改造中获取数据,然后从我的远程获取数据webservice 然后,使用领域的insertOrUpdate 将远程对象与本地对象合并。到目前为止,我能够完成这个过程,但是当我查看我在 stetho 上的网络请求时,这个方法已经完成了无限次请求。我哪里做错了?这是函数

public Observable<RealmResults<Event>> all() {
    Realm realm = Realm.getDefaultInstance();

    return realm.where(Event.class).findAllAsync()
            .asObservable()
            .filter(new Func1<RealmResults<Event>, Boolean>() {
                @Override
                public Boolean call(RealmResults<Event> events) {
                    return events.isLoaded();
                }
            })
            .doOnNext(new Action1<RealmResults<Event>>() {
                @Override
                public void call(RealmResults<Event> events) {
                    service.getEvents()
                            .subscribeOn(Schedulers.io())
                            .subscribe(new Action1<List<Event>>() {
                                @Override
                                public void call(final List<Event> events) {
                                    try(Realm realm = Realm.getDefaultInstance()) {
                                        realm.executeTransaction(new Realm.Transaction() {
                                            @Override
                                            public void execute(Realm realm) {
                                                realm.insertOrUpdate(events);
                                            }
                                        });
                                    } // auto-close
                                }
                            });
                }
            });
}

这是我的活动中的功能,我在哪里使用它

private void getEvents() {
    Log.i("EVENTSELECTION", "STARTING");
    repository.all()
            .subscribe(new Subscriber<List<Event>>() {
                @Override
                public void onCompleted() {
                    Log.i("EVENTSELECTION", "Task Completed");
                    swipeRefreshLayout.setRefreshing(false);
                }

                @Override
                public void onError(Throwable e) {
                    Log.e("EVENTSELECTION", e.getMessage());
                    swipeRefreshLayout.setRefreshing(false);
                    e.printStackTrace();
                }

                @Override
                public void onNext(List<Event> events) {
                    Log.i("EVENTSELECTION", String.valueOf(events.size()));
                }
            });
}

非常感谢。

【问题讨论】:

  • 感觉onCompleted不叫...
  • 我不明白你为什么用一个热的 observable 来做一个冷的 observable。你有一个数据库可以给你更改通知,你为什么忽略它?
  • @EpicPandaForce 抱歉,我是 rxjava 新手,还不了解冷热可观察对象,但我现在正在挖掘所有可能的资源,以便学习。非常感谢
  • Hot Observables 从不调用 onComplete 因为它们总是会发出事件。典型的基于侦听器的任何东西,例如单击侦听器、更改侦听器、文本更改侦听器等。在这里写.first() 就像只听第一个按钮点击、编辑文本中按下的第一个字母等等。这样做真的没有意义。

标签: java android realm retrofit


【解决方案1】:

我哪里做错了?

让我们来看看吧:

1.

public Observable<RealmResults<Event>> all() {
    Realm realm = Realm.getDefaultInstance(); 

这会打开一个永远不会关闭的 Realm 实例。所以你的Realm生命周期管理是错误的,参考documentation for best practices

2.

return realm.where(Event.class).findAllAsync()
        .asObservable() // <-- listens for changes in the Realm
// ...
        .doOnNext(new Action1<RealmResults<Event>>() {
            @Override
            public void call(RealmResults<Event> events) {
                service.getEvents() // <-- downloads data
                        .subscribeOn(Schedulers.io())
                        .subscribe(new Action1<List<Event>>() {

您基本上是说“如果对 Realm 中的数据进行任何更改,则从服务中下载数据并将其写入 Realm”

这将触发 RealmChangeListener 将触发下载等等。

这是一个概念性错误,您错误地使用了Realm notifications


RealmResults&lt;T&gt; 不仅仅是一个对象列表,它还是一个变更订阅。因此,您需要将其保留为字段参考,并“保持订阅数据库中的更改”。

RealmResults<Sth> results;
RealmChangeListener<RealmResults<Sth>> changeListener = (element) -> {
    if(element.isLoaded()) {
        adapter.updateData(element);
    }
};

void sth() {
    results = realm.where(Sth.class).findAllSortedAsync("id");
    results.addChangeListener(changeListener);
}

void unsth() {
    if(results != null && results.isValid()) {
        results.removeChangeListener(changeListener);
        results = null;
    }
}

在您的情况下,RealmResults&lt;T&gt; 表示订阅并提供对当前/新数据的访问权限,它被包装为您可以创建订阅者的 Observable&lt;T&gt;

Observable<List<<Sth>> results;
Subscription subscription;
Action1<List<Sth>> changeListener = (element) -> {
    if(element.isLoaded()) {
        adapter.updateData(element);
    }
};

void sth() {
    results = realm.where(Sth.class).findAllSortedAsync("id").asObservable();
    subscription = results.subscribe(changeListener);
}

void unsth() {
    if(subscription != null && !subscription.isUnsubscribed()) {
        subscription.unsubscribe();
        subscription = null; 
        results = null;
    }
}

如您所见,您在组件的开头有一个订阅,在组件的末尾有一个取消订阅。

调用Observable.first() 不正确,这样做没有意义。如果您在任何教程中看到它(我以前看过...),那么该教程是错误的。

【讨论】:

  • 是的,我已经在教程和 stackoverflow 答案中看到了,非常感谢您将其清除给我,我删除了我在领域上对可观察通知的使用,并简化了我的解决方案,例如,获取本地首先在领域上的数据,然后使用可观察的改造触发 GET 请求,当从该请求返回某些内容时,我会将数据插入或更新到领域,即使由于 no internet connection 而不会触发改造,我仍然可以获得缓存数据。非常感谢您清理。
  • 您仍然需要通过 RealmResults 更改侦听器(或作为 Observable)观察对 Realm 中数据所做的更改,因为 RealmResults 是一个会发生更改的代理视图。
  • 我会试着练习你的答案,非常感谢!
【解决方案2】:

所以它实际上是一个 by design on realm 并且它不会调用 onCompleted,我在 getEvents 函数的末尾添加了一个 .first() 以仅获得第一个结果。

【讨论】:

  • 要获得onCompleted(),而不是使用asObservable(),你只需要Observable.just(results),但通常这不是你需要的。
猜你喜欢
  • 2016-08-15
  • 2016-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
  • 2015-08-26
  • 2021-09-04
  • 2020-08-29
相关资源
最近更新 更多