Reputation: 162
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
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
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