在我的Android项目中,我使用realm作为我的数据存储引擎。我喜欢它!
我也使用RxJava,因为它使“线程化”变得如此简单,我真的很喜欢整个“反应性思维”。我喜欢它!
我使用MVP模式+一些“清洁架构”的想法来构建我的应用程序。
我的Interactors
是唯一了解Realm
的人。我在Observable的帮助下公开了数据,如下所示:
@Override
public Observable<City> getHomeTown() {
final Realm realm = Realm.getDefaultInstance();
return realm.where(City.class).equalTo("name", "Cluj-Napoca").findAllAsync().asObservable()
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
realm.close();
}
})
.compose(new NullIfNoRealmObject<City>());
}
问题是我的doOnUnsubscribe
副作用在Realm
能够做到这一点之前被调用,处理暴露的observable:
Caused by: java.lang.IllegalStateException: This Realm instance has already been closed, making it unusable.
at io.realm.BaseRealm.checkIfValid(BaseRealm.java:344)
at io.realm.RealmResults.removeChangeListener(RealmResults.java:818)
at io.realm.rx.RealmObservableFactory$3$2.call(RealmObservableFactory.java:137)
at rx.subscriptions.BooleanSubscription.unsubscribe(BooleanSubscription.java:71)
at rx.internal.util.SubscriptionList.unsubscribeFromAll(SubscriptionList.java:124)
at rx.internal.util.SubscriptionList.unsubscribe(SubscriptionList.java:113)
at rx.Subscriber.unsubscribe(Subscriber.java:98)
at rx.internal.util.SubscriptionList.unsubscribeFromAll(SubscriptionList.java:124)
at rx.internal.util.SubscriptionList.unsubscribe(SubscriptionList.java:113)
at rx.Subscriber.unsubscribe(Subscriber.java:98)
at rx.subscriptions.CompositeSubscription.unsubscribeFromAll(CompositeSubscription.java:150)
at rx.subscriptions.CompositeSubscription.unsubscribe(CompositeSubscription.java:139)
at ro.tudorluca.realm.sandbox.city.CityPresenter.onDestroy(CityPresenter.java:62)
at ro.tudorluca.realm.sandbox.city.CityActivity.onDestroy(CityActivity.java:35)
我为此用例创建了一个sandbox项目。
我真的很喜欢使用Realm + RxJava,但是当close
(我通常在活动被销毁时取消订阅)时,我似乎无法找到unsubscribe
Realm实例的干净解决方案。有什么想法吗?
修改1 :https://github.com/realm/realm-java/issues/2357
编辑2 :感谢非常活跃的领域团队,已经有pull request来解决此问题。
答案 0 :(得分:2)
21小时后,这就是我想出的:
@Override
public Observable<City> getHomeTown() {
return getManagedRealm()
.concatMap(new Func1<Realm, Observable<City>>() {
@Override
public Observable<City> call(Realm realm) {
return realm.where(City.class).equalTo("name", "Cluj-Napoca").findAllAsync().asObservable()
.compose(new NullIfNoRealmObject<City>());
}
});
}
private static Observable<Realm> getManagedRealm() {
return Observable.create(new Observable.OnSubscribe<Realm>() {
@Override
public void call(final Subscriber<? super Realm> subscriber) {
final Realm realm = Realm.getDefaultInstance();
subscriber.add(Subscriptions.create(new Action0() {
@Override
public void call() {
realm.close();
}
}));
subscriber.onNext(realm);
}
});
}
我在stackoverflow上发布问题之前尝试了类似的东西,但我的错误是使用了flatMap()
,而不是concatMap()
。
与flatMap()
不同,concatMap()
将保留排放顺序,在我的情况下,这意味着我的Action0 -> realm.close()
将是从流中取消订阅后调用的最后一个操作,之后导致问题的领域Action0 -> results.removeChangeListener(listener)
。
可以在github上找到完整的示例。
修改:感谢非常活跃的领域团队,已经有pull request来解决此问题。
答案 1 :(得分:0)
由于您说只有 Interactor “知道”有关Realm框架的信息我会说甚至不返回托管的Realm对象,而是使用copyFromRealm
返回结果的非托管副本。这样您就不必关心 Presenter 中正在打开或关闭的Realm实例。
与此同时,我会让 Presenter 选择是否应该以异步方式完成调用,因为RxJava
非常酷而且很容易调用另一个线程中的 Interactor 加载方法(使用Loopers可以避免使用它,但如果你可以使它变得更简单,为什么会使情况过于复杂化:P)。
所以我会选择:
Override
public Observable<City> getHomeTown() {
final Realm realm = Realm.getDefaultInstance();
City city = realm.where(City.class).equalTo("name", "Cluj-Napoca").findFirst();
// make sure we don't send back Realm stuff, this is a deep copy that will copy all referenced objects (as the method doc says)
City cityUnmanaged = realm.copyFromRealm(city);
// safe to close the realm instance now
realm.close();
return Observable.just(cityUnmanaged);
}
我很想看到更多选择:)。
答案 2 :(得分:0)
按照我的说法,在一个好的架构中要照顾的主要事情之一就是模块化。所有主要模块(或库)都应与其余代码隔离。由于Realm,RealmObject或RealmResult不能跨线程传递,因此制作Realm&amp;与其余代码隔离的领域相关操作。
牢记这一理念,我提出了以下方法。
对于每个jsonModel类,我们创建一个realmModel类和一个DAO(数据访问对象)类。这里的想法是除了DAO类之外,没有类必须知道或访问realmModel或Realm实体。 DAO类接受jsonModel,将其转换为realmModel,执行读/写/编辑/删除操作&amp;对于读取操作,DAO将生成的realmModel转换为jsonModel并返回它们。
这样很容易维护Realm,避免所有与线程相关的问题,易于测试和调试。
这是一篇关于Realm最佳实践的文章,其中有一个很好的架构https://medium.com/@Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f
此外,一个示例项目演示了Android上的Realm与MVP(模型视图演示者),RxJava,Retrofit,Dagger,Annotations&amp;测试。 https://github.com/viraj49/Realm_android-injection-rx-test