RealmObject 实例被多次调用
RealmObject instance being invoked multiple times
我正在使用 Realm + Retrofit2
我正在尝试执行以下操作:
- UI 向 DataManger 请求数据。
- DataManger returns缓存数据,检查数据是否过期然后调用新数据。
- 当新数据保存在 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()
的操作,因为它只会发出一次然后完成,但这取决于您的用例是否可以接受。
我正在使用 Realm + Retrofit2 我正在尝试执行以下操作:
- UI 向 DataManger 请求数据。
- DataManger returns缓存数据,检查数据是否过期然后调用新数据。
- 当新数据保存在 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()
的操作,因为它只会发出一次然后完成,但这取决于您的用例是否可以接受。