RealmObject 实例被多次调用

RealmObject instance being invoked multiple times

我正在使用 Realm + Retrofit2 我正在尝试执行以下操作:

  1. UI 向 DataManger 请求数据。
  2. DataManger returns缓存数据,检查数据是否过期然后调用新数据。
  3. 当新数据保存在 Realm NetworkManager 中时触发事件,该事件被 UI 捕获以更新数据。

问题

当NetworkHelper在Realm中保存数据时,由于RealmObjects的onChangeListeners,在commitTransaction()之后,DataManger onCall()部分的代码再次执行,再次调用NetworkHelper获取新数据,随后又从网络和进程进入无限循环。我在多个点尝试了 gitHubUser.removeChangeListeners() 但它仍然无法正常工作。请指出任何根本错误或使用 Realm 实现的正确方法。

实现代码如下:

DataManager

 public Observable<GitHubUser> getGitHubUser(final String user){

    return databaseHelper.getGitHubUser(user).doOnNext(new Action1<GitHubUser>() {
        @Override
        public void call(GitHubUser gitHubUser) {
            if(gitHubUser==null || !isDataUpToDate(CACHE_TIME_OUT,gitHubUser.getTimestamp())){
                if(gitHubUser!=null)
                    System.out.println("isDataUpToDate = " + isDataUpToDate(CACHE_TIME_OUT,gitHubUser.getTimestamp()));
                networkHelper.getGitHubUserRxBus(user);
            }
        }
    });
}

DataBaseHelper

public Observable<GitHubUser> saveGitHubUser(GitHubUser user, String userId) {
    realmInstance.beginTransaction();
    user.setUserId(userId);
    user.setTimestamp(System.currentTimeMillis());
    GitHubUser userSaved = realmInstance.copyToRealm(user);
    Observable<GitHubUser> userSavedObservable = userSaved.asObservable();
    realmInstance.commitTransaction();
    return userSavedObservable;
}

public Observable<GitHubUser> getGitHubUser(String user){
    System.out.println("DatabaseHelper.getGitHubUser");
    GitHubUser result = realmInstance.where(GitHubUser.class).contains("userId",user, Case.INSENSITIVE).findFirst();
    if(result != null){
        return result.asObservable();
    }else{
        return Observable.just(null);
    }
}

网络助手

  public void getGitHubUserRxBus(final String user){
    System.out.println("NetworkHelper.getGitHubUserRxBus");
    retroFitService.user(user)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .flatMap(new Func1<GitHubUser, Observable<GitHubUser>>() {
                @Override
                public Observable<GitHubUser> call(GitHubUser gitHubUser) {
                    System.out.println("NetworkHelper.call");
                    return databaseHelper.saveGitHubUser(gitHubUser,user);
                }
            }).subscribe(new Action1<GitHubUser>() {
        @Override
        public void call(GitHubUser gitHubUser) {

            if (rxBus.hasObservers()) {
                System.out.println("NetworkHelper.call");
                rxBus.send(gitHubUser);
            }
        }
    });
}

Activity

  subscription.add(dataManager.getGitHubUser("gitHubUserName")
            .subscribe(new Subscriber<GitHubUser>() {
        @Override
        public void onCompleted() {
            System.out.println("LoginActivity.call" + " OnComplete");
        }

        @Override
        public void onError(Throwable e) {
            System.out.println("throwable = [" + e.toString() + "]");
        }

        @Override
        public void onNext(GitHubUser gitHubUser) {
            System.out.println("LoginActivity.call" + " OnNext");
            if (gitHubUser != null) {
                sampleResponseText.setText(gitHubUser.getName() + " timestamp " + gitHubUser.getTimestamp());
            }
            onCompleted();

        }
    }));
subscription.add(rxBus.toObserverable().subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
            if(o instanceof GitHubUser){
                GitHubUser gitHubUser = ((GitHubUser)o);
                sampleResponseText.setText(gitHubUser.getName() + " time " + gitHubUser.getTimestamp());
            }
        }
    }));

更新

最后在 DataManger 中解决了这个问题:

return Observable.concat(databaseHelper.getGitHubUser(user).take(1),
                             networkHelper.getGitHubUser(user))
                    .takeUntil(new Func1<GitHubUser, Boolean>() {
                        @Override
                        public Boolean call(GitHubUser gitHubUser) {
                            boolean result = gitHubUser!=null && isDataUpToDate(CACHE_TIME_OUT,gitHubUser.getTimestamp());
                            System.out.println("isDataUpToDate = " + result);
                            return result;
                        }
                    });

我认为你的代码中有一个循环:

1) 您从 getGithubUser() 中的 RealmResults 创建一个 observable。每次您更改可能影响它们的数据时,Realm observable 都会发出。

2) 从 Realm 检索用户后调用 networkHelper.getGitHubUserRxBus(user)

3) 从网络获取用户时,将其保存到 Realm,这将触发在 1) 中创建的 Observable 再次发射,从而创建您的循环。

要打破它,您可以在 getGitHubUser() 中执行类似 result.asObservable().first() 的操作,因为它只会发出一次然后完成,但这取决于您的用例是否可以接受。