Orma v4.0.0 - RxJava2 & SQLBrite-like query observables

GitHub - gfx/Android-Orma: A type-safe ORM for Android as a wrapper of SQLiteDatabase

v3.0.0からまだ一ヶ月くらいしかたってませんが、Ormaがv4.0.0となりました。

目玉機能は RxJava 2.x 対応で、これが後方互換性を維持したまま行うのが難しかったため、メジャーバージョンを上げることにしました。

RxJava 2.x 対応

機能的にはRxJava 1.x対応と同じ水準なはずです。

ただこれを機に、 Observable を返すものは AsObservable をサフィックスに、 SingleAsSingle に、 CompletableAsCompletableに…と、メソッド名を見ればRx observableのどの亜種を返すのかを分かるようにしました。

Query Observables

この機能は実験的です。いきなり消えることはないと思いますが、微妙にインターフェイスが変化したりする可能性があります。またこの機能の使い心地についてフィードバックを求めています!

SQLBriteのように、データセットの変更が流れるイベントストリームをRxJavaのobservableとして作成できます。このobservableを購読すると、Ormaによるデータの更新(INSERT, UPDATE, DELETE)を受け取れます。またその際Selectorを引数として受け取りますが、これはただのSelectorなので使っても使わなくてもかまいません。使い方の具体例としてはOrmaRecyclerViewAdapterなどがあります。

SQLBriteと違って完全にRx任せなので、デフォルトで同期的に変更通知が流れます。非同期で処理したい場合は、Rxのschedulersを使ってスレッドを調整してください。またこれもSQLBriteはsubscribe() した瞬間に最初のイベントがながれますが、Ormaは何も流れません。Ormaはあくまでも変更通知だけを流します。

READMEから抜粋:

// NOTE: Keep the observable instance. If it's released, the observable is disposed.

// create a query observable, which is a hot observable
Observable<Author_Selector> observable = db.relationOfAuthor()
        .createQueryObservable();

// subscribe the events
observable.flatMap(new Function<Author_Selector, Observable<Author>>() {
    @Override
    public Observable<Author> apply(Author_Selector selector) throws Exception {
        Log.d(TAG, "Author has been changed!");
        return selector.executeAsObservable();
    }
})
        .map(new Function<Author, String>() {
            @Override
            public String apply(Author author) throws Exception {
                return author.name;
            }
        })
        .subscribe(new Consumer<String>() {
            @Override
            public void accept(String name) throws Exception {
                Log.d(TAG, "name: " + name);
            }
        });

注意点としては、 createQueryObservable() の戻り値を強参照として保持しておく必要があります。そうでなければ、GCのタイミングで消えてしまいます。また、変更通知が伝播するのは同一のデータベースハンドル(OrmaDatabaseのインスタンス)の間だけです。つまり、プロセス間ではイベントが伝播しません。

また、実験的に createEventObservable() というメソッドも用意していて、こちらはイベントの種類(INSERT / UPDATEなど)もとれます。ただし、@Deprecatedマークをしてあるとおり、これは本当に実験的で、これについてどこからも意見がなければどこかのバージョンで消すと思います。