2016-02-26 46 views
12

在我的Android项目中,我使用realm作为我的数据存储引擎。我喜欢它!
我也使用RxJava,因为它使得“线程化”变得更容易,而且我非常喜欢整个“反应性思维模式”。我喜欢它!
Realm,RxJava,asObservable()和doOnUnsubscribe()

我使用MVP模式+一些“清洁架构”的想法来构建我的应用程序。

我的Interactors是唯一知道Realm的人。我公开数据与可观察的帮助下,像这样:

@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之前调用可以做的事情,处理暴露观察到:

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项目。

我真的很喜欢使用领域+ RxJava,但我似乎无法找到一个干净的解决方案,以close的领域实例时,我unsubscribe(我平时活动时被破坏退订)。有任何想法吗?

编辑1https://github.com/realm/realm-java/issues/2357
编辑2:多亏了非常积极的境界团队,已经有一个pull request来解决这个问题。

回答

1

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

我想是这样的张贴计算器面前的问题,但是我的错用,而不是concatMap()flatMap()

不像flatMap()concatMap()将保持排放的加入顺序,于我而言,意味着我的Action0 -> realm.close()将是最后一个动作从流订阅后,被称为,境界的Action0 -> results.removeChangeListener(listener)这是造成问题的原因后。

完整的示例可在github上找到。

编辑:感谢非常活跃的领域团队,已经有一个pull request来解决这个问题。

+0

考虑通过Observable#使用包装Realm,这将简化您的getManagedRealm()方法:http://pastebin.com/CrzryvCq –

+0

我尝试您的解决方案并遇到问题:在领域文件中打开太多 –

0

既然你说,只有交互器“知道”的境界框架,我会说没有,甚至返回一个管理域的对象,而不是返回使用copyFromRealm结果的非托管副本。这样,您不必关心在Presenter中正在打开或关闭的Realm实例。

同时我先给演示选择羯羊电话应做异步或不因为RxJava确实是很酷,很容易,你不会有调用另一个线程内交互器负荷法问题(可以使用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); 
} 

我很好奇,看看更多的选择:)。

+1

返回Observable ,我的Interactor完全包含“反应性思维模式”。当您执行查询时,Interactor将返回一个数据流,该数据流将在数据准备就绪并可用时推送数据。当新数据可用时,返回的流已准备好推送您的数据。就我而言,每次有人推送更改到领域时,我都会得到一个更新的城市。 “自动刷新”是Realm的核心功能,也是一个非常不错的功能。 –

+0

此外,copyFromRealm()是确定了我的演示,因为我的对象是小的,没有关系。但在现实生活中,我有一个复杂的对象图,我真的不想将它们全部加载到内存中。 “Lazy + no-copy data”是Realm的另一个核心功能,您应该尽可能充分利用它。 –

+0

领域有一个“线程”的限制,你不能用RxJava来处理多线程查询。还有就是你可以探索更多的陷阱一个很好的例子项目:https://github.com/realm/realm-java/blob/master/examples/rxJavaExample/src/main/java/io/realm/examples/rxjava/gotchas /GotchasActivity.java –

0

正如我所看到的,在一个好的架构中要考虑的重点是模块化。所有主要模块(或库)应与代码的其余部分隔离。由于境界,RealmObject或RealmResult不能跨线程传递,它更重要的是使从代码的其余部分隔离境界&领域的相关业务。

坚持这一理念,我提出了以下方法。

对于每个jsonModel类,我们创建一个realmModel类和一个DAO(数据访问对象)类。这里的想法是,除了DAO类以外,没有任何类必须知道或访问realmModel或Realm实体。 DAO类需要jsonModel,将其转换为realmModel,执行读/写/修改/删除操作&对于读操作DAO转换导致realmModel到jsonModel并返回它们。

这种方式很容易维护Realm,避免所有线程相关的问题,易于测试和调试。

以下是有关领域的最佳实践的文章具有良好的architechture https://medium.com/@Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f

另外一个示例项目演示领域的整合在Android上MVP(模型视图演示),RxJava,改造,匕首,注解&测试。 https://github.com/viraj49/Realm_android-injection-rx-test