Zeatual Chang
Zeatual Chang

Reputation: 162

What is the best practice of managing realm instance in Clean Architecture?

My project using clean architecture. In this situation, the UI layer is separate from Domain layer. So I think it would be better the UI layer doesn't own realm instance. As realm's doc recommend managing the realm instance in Activity's lifecycle, how should I deal with the realm instance then?

To be more clear, my project is too heavy to change all objects extends RealmObject. So I use separate object to persistent data. When the api call finish, a business object convert to a realm object, opposite when query from realm. I create the method like this:

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

Actually, it works fine. But below I don't know how to handle closing realm instance.

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

Upvotes: 6

Views: 3060

Answers (2)

Viraj Tank
Viraj Tank

Reputation: 1285

One of the major aspect of a clean architecture is, isolation of major libraries (i.e. Realm). Since Realm, RealmObject, RealmResults are not accessible outside of the Thread they are created in, it makes it even more important to keep Realm & Realm related calculations isolated from rest of the code.

You are using RxJava in your queryAsync() method, and at the same time you are using executeTransactionAsync() method, which defies the whole purpose of using RxJava. You could have done like this,

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

In a good Architecture, for each jsonModel class there should be a corresponding realmModel class & a DAO (Data Access Object). DAO class must take jsonModel as argument and must return jsonModel as result. All Realm related operations must be restricted within the DAO file, that way none of the code other than DAO and realmModel knows about Realm.

Here is an article about Realm best practices with a good architechture https://medium.com/@Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f

Also a sample project demonstrating Integration of Realm on Android with MVP(Model View Presenter), RxJava, Retrofit, Dagger, Annotations & Testing. https://github.com/viraj49/Realm_android-injection-rx-test

Upvotes: 0

Tim
Tim

Reputation: 43364

If you want a clean separation between UI and database layers in your code, and you want to abstract away your database logic so that ideally your activity can call database layer without knowing how that layer is implemented, then Realm is probably not what you're looking for.

Realm objects are tied to realm instances which means that if you retrieve an object from a realm instance and then close that instance (which you must), you can no longer use the object. Which defeats the entire purpose of using Realm.

If you are going to use Realm, you should keep the realm logic closely tied to your activities/services etc, and don't try to hide it in a separate layer, so that you have full control over it.


        .map(new Func1<RealmObject, T>() {
            @Override
            public T call(RealmObject realmObject) {
                Object o = createObjectFromRealm(realmObject);
                realm.close();
                return o;
            }
        });

Upvotes: 4

Related Questions