Skip to content
This repository has been archived by the owner on May 1, 2020. It is now read-only.

Listening for data changes

Sam Bosley edited this page Oct 29, 2015 · 7 revisions

SquidDatabase allows users to listen for changes to tables using DataChangedNotifier objects. DataChangedNotifier instances are constructed with a list of tables they are interested in listening to (or an empty list to listen to all tables):

// For listening to the people table
DataChangedNotifier<T> personNotifier = new DataChangedNotifier<T>(Person.TABLE) {
    ...
}

// For listening to all tables
DataChangedNotifier<T> globalNotifier = new DataChangedNotifier<T>() {
    ...
}

The general principle of DataChangedNotifier is to accumulate objects representing the notifications to be sent during a transaction, and then send them all on successful transaction completion. It is an abstract class, so users are free to override it and implement data changed notifications in whatever way they see fit. However, SquiDB provides a few built-in implementations of DataChangedNotifier to cover some common use cases.

UriNotifier

UriNotifier can help you listen for and respond to database changes using the standard Android ContentObserver mechanism. When you create an instance of UriNotifier, you will have to override the accumulateNotificationObjects method. In this case, the objects to be accumulated are the Uris to be notified. Using information provided by the SquidDatabase about what kind of write occurred, you can construct a Uri and add that Uri to the accumulator set:

UriNotifier peopleNotifier = new UriNotifier(Person.TABLE) {
    @Override
    protected abstract boolean accumulateNotificationObjects(Set<Uri> accumulatorSet,
        SqlTable<?> table, SquidDatabase database, DBOperation operation,
        AbstractModel modelValues, long rowId) {
        // Notifies some constant Uri for any update on the people table
        accumulatorSet.add(Person.CONTENT_URI);
     }
}

Any Uri you add to the accumulatorSet set will get a notification once the currently running transaction has completed successfully.

Note: Uris like Person.CONTENT_URI will not be generated automatically, but if you declare them (or anything else) as public static final fields in your model spec classes they'll be copied to the generated model.

Listening for Uri changes

Generally, you'll probably want to listen for changes using an instance of SquidCursorLoader, so that your cursors will automatically be reloaded. This is pretty easy too--when constructing your SquidCursorLoader, just call setNotificationUri:

SquidCursorLoader<Student> loader = new SquidCursorLoader(context, database, Person.class,
    Query.select(Person.PROPERTIES));

loader.setNotificationUri(Person.CONTENT_URI);

Of course, you can also manually call [ContentResolver.registerContentObserver](http://developer.android.com/reference/android/content/ContentResolver.html#registerContentObserver(android.net.Uri,%20boolean,%20android.database.ContentObserver) to register your own ContentObservers on Uris as well.

SimpleDataChangedNotifier

SimpleDataChangedNotifier allows you to run arbitrary code on successful transaction completion. It doesn't care what changes occurred, only that some write occurred on the table(s) it listens to:

final AtomicInteger callCount = new AtomicInteger(0);
SimpleDataChangedNotifier simpleNotifier = new SimpleDataChangedNotifier(Person.TABLE) {
    @Override
    protected void onDataChanged() {
        callCount.incrementAndGet();
    }
}

In this example, callCount will be incremented once for every transaction that writes to the people table.

Registering DataChangedNotifier to a SquidDatabase

This is pretty easy--just call registerDataChangedNotifier on your SquidDatabase instance. Generally, you'll probably want to register these at instantiation time, since we highly recommend that your database objects be singletons:

MyDatabase database = new MyDatabase(context);
database.registerUriNotifier(peopleNotifier);

See also: