在清洁架构中,管理 Realm 实例的最佳实践是什么?

6
我的项目采用了清晰的架构。在这种情况下,UI层与域层是分离的。因此,我认为最好将UI层不与Realm实例相关联。由于Realm文档建议在Activity的生命周期中管理Realm实例,那么我应该如何处理Realm实例呢?
更明确地说,我的项目太重了,无法改变所有对象继承自RealmObject。因此,我使用独立的对象持久化数据。当API调用完成时,业务对象转换为Realm对象,反之亦然。我创建了以下方法:
public void insert(T object){
    final Realm realm = RealmProvider.getRealm();
    realm.executeTransactionAsync(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.copyToRealmOrUpdate(createRealmObject(object));
        }
    }, new Realm.Transaction.OnSuccess() {
        @Override
        public void onSuccess() {
            realm.close();
        }
    }, new Realm.Transaction.OnError() {
        @Override
        public void onError(Throwable error) {
            realm.close();
        }
    });
}

实际上,它运行良好。但是下面我不知道如何处理关闭领域实例。

public Observable<T> queryAsync(Condition<? extends RealmObject> condition) {
    final Realm realm = RealmProvider.getRealm();
    return condition.getQuery(realm).findFirstAsync()
            .asObservable()
            .filter(new Func1<RealmObject, Boolean>() {
                @Override
                public Boolean call(RealmObject realmObject) {
                    return realmObject.isLoaded();
                }
            })
            .map(new Func1<RealmObject, T>() {
                @Override
                public T call(RealmObject realmObject) {
                    return createObjectFromRealm(realmObject);
                }
            });
}
2个回答

4
如果您想在代码中实现UI和数据库层之间的清晰分离,并希望将数据库逻辑抽象化,以便活动可以调用数据库层而不必了解该层的实现方式,则Realm可能并非您所需。
Realm对象与Realm实例绑定,这意味着如果您从一个Realm实例中检索对象,然后关闭该实例(必须这样做),则无法再使用该对象,这违背了使用Realm的整个目的。
如果您要使用Realm,则应将Realm逻辑与您的活动/服务等紧密联系起来,不要试图将其隐藏在单独的层中,以便您可以完全控制它。
        .map(new Func1<RealmObject, T>() {
            @Override
            public T call(RealmObject realmObject) {
                Object o = createObjectFromRealm(realmObject);
                realm.close();
                return o;
            }
        });

谢谢回复。我在上面更新了一些细节。我理解这样做会放弃realm的许多优势。但是项目的架构已经确定,所以在这种情况下使用realm是否可能? - Zeatual Chang
@ZeatualChang 我想象call是链中的最后一个函数,所以你可以在那里关闭领域,参见编辑。这可能有效。 - Tim
我已经尝试过这个,但是Rx操作符在异步查询所在的线程上运行,而该线程与打开Realm实例的线程不同。 - Zeatual Chang
@ZeatualChang 尝试在“正常”线程上制作一个循环器,并在 call 中通过引用该循环器在“正常”线程上运行代码。 - Tim

0

一个干净架构的主要方面之一是隔离主要库(例如Realm)。由于Realm、RealmObject和RealmResults在创建它们的线程之外不可访问,因此将Realm及其相关计算与其他代码隔离开来变得更加重要。

您在queryAsync()方法中使用了RxJava,同时又使用了executeTransactionAsync()方法,这违背了使用RxJava的初衷。您可以像这样做:

public void insert(T object){
    final Realm realm = RealmProvider.getRealm();
    realm.executeTransaction(realm1 -> 
    realm1.copyToRealmOrUpdate(createRealmObject(object)));
    realm.close();
}

在一个良好的架构中,每个jsonModel类都应该有一个相应的realmModel类和DAO(数据访问对象)。DAO类必须以jsonModel作为参数,并返回jsonModel作为结果。所有与Realm相关的操作必须限制在DAO文件中,这样除了DAO和realmModel之外的代码都不知道Realm。
这是一篇关于Realm最佳实践的文章,其中包含一个良好的架构https://medium.com/@Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f
此外,还有一个示例项目,演示了在Android上使用MVP(模型视图Presenter)、RxJava、Retrofit、Dagger、注释和测试集成Realm。 https://github.com/viraj49/Realm_android-injection-rx-test

当使用这种方法时,你放弃了realm的哪些功能? - Tim
就我所知,您可以在不遗漏任何内容的情况下执行所有Realm操作,其主要重点是将所有Realm内容与代码的其余部分隔离开来。 - Viraj Tank
@Tim,经过长时间的讨论和更多的发现,结果发现您在使用隔离方法时错过了一些Realm功能。例如,当修改RealmObject时,Realm会自动更新视图。 - Viraj Tank
没错。我发现这是一个很大的劣势。 - Tim
确实,但另一方面,您必须在主线程上执行Realm操作,这对我来说似乎是更大的威胁。 - Viraj Tank
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接