简体   繁体   English

RxJava + Retrofit + Realm正在进行无限制的get请求

[英]RxJava + Retrofit + Realm is doing unlimited get request

I am completely new to rxJava and it's really confusing, I want to make my app offline first and I've decided to use Realm and Retrofit, First I want to get the data from retrofit and then get the data from my remote webservice then, use realm's insertOrUpdate to merge the remote objects with the local one. 我对rxJava是全新的,它真的很混乱,我想让我的应用程序首先离线,我决定使用Realm和Retrofit,首先我想从改造中获取数据,然后从我的远程web服务获取数据,使用realm的insertOrUpdate将远程对象与本地对象合并。 I'm able to get on this process so far but when I looked into my Network requests on stetho, this method is complete requesting infinite times. 到目前为止,我能够开始这个过程,但是当我在stetho上查看我的网络请求时,这个方法完成了请求无限次。 Where did I go wrong? 我哪里做错了? Here's the function 这是功能

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
                                }
                            });
                }
            });
}

and here's the function on my activity, where I use it 这是我活动的功能,我在哪里使用它

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()));
                }
            });
}

Thank you so much. 非常感谢。

Where did I go wrong? 我哪里做错了?

Let's go through it: 我们来看看吧:

1. 1。

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

This opens a Realm instance that will never be closed. 这将打开永远不会关闭的Realm实例。 So your Realm lifecycle management is wrong, refer to the documentation for best practices . 因此,您的Realm生命周期管理是错误的,请参阅文档以获取最佳实践

2. 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>>() {

You basically say that "in case there are any changes made to data in Realm, then download data from the service and write it into the Realm" 您基本上说“如果Realm中的数据有任何更改,那么从服务下载数据并将其写入Realm”

Which will trigger the RealmChangeListener which will trigger a download and so on. 这将触发将触发下载等的RealmChangeListener。

This is a conceptual error, you're using Realm notifications incorrectly. 这是一个概念性错误,您错误地使用了Realm通知


RealmResults<T> is not just a list of objects, it is also a subscription for changes. RealmResults<T>不仅仅是一个对象列表,它还是一个变更订阅。 So you need to keep it as a field reference, and "stay subscribed to changes in the database". 因此,您需要将其保留为字段引用,并“保持订阅数据库中的更改”。

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;
    }
}

In your case, RealmResults<T> which symbolizes a subscription and also provides access to the current/new data is wrapped as an Observable<T> which you can create subscribers to. 在您的情况下, RealmResults<T>表示订阅并且还提供对当前/新数据的访问,它被包装为Observable<T> ,您可以创建订阅者。

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;
    }
}

As you can see, you have a subscription at the start of the component, and an unsubscription at the end of the component. 如您所见,您在组件的开头有一个订阅,在组件的末尾有一个取消订阅。

Calling Observable.first() is incorrect, it does not make sense to do that. 调用Observable.first()是不正确的,这样做是没有意义的。 If you saw it in any tutorial (I've seen it before...), then that tutorial was wrong. 如果您在任何教程中看到它(我之前已经看过它......),那么该教程是错误的。

所以它真的是一个by design的领域而且它不会调用onCompleted,我在getEvents函数的末尾添加了一个.first()来获得第一个结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM