Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Realm.io [Java] notifications - How to listen for changes only in certain Table?

I see this example code in realm java documentation.

public class MyActivity extends Activity {
    private Realm realm;
    // A reference to RealmChangeListener needs to be held to avoid being
    // removed by the garbage collector.
    private RealmChangeListener realmListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      realm = Realm.getDefaultInstance();
      reamlListener = new RealmChangeListener() {
        @Override
        public void onChange() {
            // ... do something with the updates (UI, etc.) ...
        }};
      realm.addChangeListener(realmListener);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Remove the listener.
        realm.removeChangeListener(realmListener);
        // Close the realm instance.
        realm.close();
    }
}

I have some database schema contain several tables. Data is always changing in these tables but I have only the one table I need to listen and refresh UI related to this table. I don't want to check is this changes in Realm was exactly in wanted table after any little updating in any other Realm Objects. What best practices can you suggest?

like image 534
Yura Buyaroff Avatar asked Sep 12 '15 01:09

Yura Buyaroff


2 Answers

Until Realm has fine-grained notifications, I would implement my own notification system either by using ContentObserver, RxJava or your own Observer interfaces.

like image 141
Christian Melchior Avatar answered Oct 23 '22 03:10

Christian Melchior


As said Christian RxJava is can help. Though of course is rather a concept that may require major changes in the code than concrete and rapid solution to the problem. In any case Repository pattern for access to our database is good practice. You can use own layer for access to the Realm. In this case you can control query to the Realm and notify observers if data changed.

    public interface RealmRepository {
            <T> Observable<T> get(Class clazz, Func1<RealmQuery, RealmQuery> predicate);
            void storeObject(Class clazz, JSONObject jsonObject);
            void storeObjects(Class clazz, JSONArray jsonArray);
            <T> Observable<T> update(Class clazz, Action0 action);
         }

Using the Realm interface repository allows you to ensure that you are control all requests.

Now you will get Observable<T> object and can notify if data changed.

    public class RealmRepositoryImpl implements RealmRepository {

    Realm realm;
    RealmQueryableCollection realmQueryCollection;

    public RealmRepositoryImpl(Realm realm) {
        this.realm = realm;
        this.realmQueryCollection = new RealmQueryableCollection();
    }

    @Override
    public <T> Observable<T> get(Class clazz, Func1<RealmQuery, RealmQuery> predicate) {
        BehaviorSubject<T> behaviorSubject = BehaviorSubject.create((T) getInner(clazz, predicate));
        realmQueryCollection.add(clazz, predicate, behaviorSubject);
        return behaviorSubject;
    }

    public <T extends RealmObject> RealmResults<T> getInner(Class clazz, Func1<RealmQuery, RealmQuery> predicate) {
        RealmQuery query = realm.where(clazz);
        if (predicate != null)
            query = predicate.call(query);
        return query.findAll();
    }

    @Override
    public void storeObject(Class clazz, JSONObject jsonObject) {
        realm.beginTransaction();
        realm.createOrUpdateObjectFromJson(clazz, jsonObject);
        realm.commitTransaction();
        notifyObservers(clazz);

    }

    @Override
    public void storeObjects(Class clazz, JSONArray jsonArray) {
        realm.beginTransaction();
        realm.createOrUpdateAllFromJson(clazz, jsonArray);
        realm.commitTransaction();
        notifyObservers(clazz);
    }


    @Override
    public <T> Observable<T> update(Class clazz, Action0 action) {
        return (Observable<T>) Observable.create(subscriber -> {
            realm.beginTransaction();
            action.call();
        }).doOnNext(o -> {
            realm.commitTransaction();
            notifyObservers(clazz);
        });
    }

    private void notifyObservers(Class clazz) {
        Observable.from(realmQueryCollection.getQuerables(clazz))
                .subscribe(realmQuerable ->
                        realmQuerable.getSubject().onNext(getInner(clazz, realmQuerable.getPredicate())));
    }
}

When make get query you just save entity (table), predicate (nice rx.functions.Func1) and subject. When you will change the data in the Realm you can get changed data with saved predicate and notify about changes all observers.

Example get query

public Observable<List<Event>> getEvents() {
        return realmRepository.get(Event.class, predicate -> predicate
                        .equalTo("category", "Art")
                        .or()
                        .equalTo("category", "Music"));
    }

In my opinion a reactive approach is a natural solution to this problem.

Full sample code on GitHub you can try to play with the example. At the moment it is not complete solution (no notification unsubscribe, etc), but rather just an idea.

like image 33
Alexandr Avatar answered Oct 23 '22 05:10

Alexandr