Realm Java 3.1: オブジェクト通知、バックアップからの復元、逆向きの関連

本バージョンではRealmファイルのフォーマットが変更されているため、以前のバージョンのRealmから開くことはできなくなります。以前のバージョンで作成したRealmファイルは、このバージョンでオープンする際に自動的にフォーマットが更新されます。既存のアプリを更新する際は十分ご注意ください。

Realm Java 3.1をリリースしました。このリリースには、単一のオブジェクトに対する詳細な通知、同期しているRealmのデータをサーバー上で復元を行った際の回復手段の提供、関連を逆方向にたどる機能が含まれます。それぞれについて説明します。

単一のオブジェクトに対する詳細な通知

Realm Java 3.0では、コレクションに対する詳細な通知機能をリリースしました。3.1では、この詳細な通知機能を単一のオブジェクトに対しても提供します。この機能のために、RealmObjectChangeListenerインターフェースとObjectChangeSetクラスを追加しました。

Person p = realm.where(Person.class).findFirst();
p.addChangeListener(new RealmObjectChangeListener<Person>() {
   @Override
   public void onChange(Person person, ObjectChangeSet changeSet) {
       if (changeSet.isDeleted()) {
           hide(); // オブジェクトが削除された
       } else {
           // どのフィールドに変更があったかがわかるため、UIを部分的に更新することも可能です
           if (changeSet.isFieldChanged("name")) {
               updateName(person.getName());
           }
       }
   }
});

記事の更新情報を受け取る

これまで提供されていた単一オブジェクトの通知機能では、実際にはそのオブジェクトのどのフィールドも更新されていないのに通知を発生させてしまうことがありました。この点も3.1で修正されています。つまり、単一のオブジェクトに対する通知は、従来の通知機能、新規に追加された詳細な通知機能にかかわらずそのオブジェクトに実際に変更がなされた場合のみ通知が呼ばれるようになります。

バックアップを復元した際の回復手段の提供

サーバー側で問題が発生した場合、正常な状態に回復させるための備えが必要です。そのため、Realm Mobile Platformでは数か月前にデータのバックアップ機能を提供しました。通常の状態では、Realmの同期エンジンは変更操作の内容のみをやり取りします。変更内容を各クライアントが受け取ったことが確認されると、サーバー上では変更ログを処分することでディスクの効率的な利用と高速化を実現します⚡️。

さらに、Realmはオフラインファーストなデータベースなので、仮に何らかの理由でサーバーがダウンしたとしてもすべてのローカルデータは依然として利用可能です。

しかし、サーバー上でバックアップからの復元が行われると、クライアントはセッションエラーハンドラーを通じて”client reset”エラーを受け取ることになります。バックアップからの復元が発生した場合であってもデータベースを使い続けることはできますが、バックアップ時点以降の変更は破棄されます。

“client reset”エラーを受け取った際、必要に応じてユーザーに状況を報告してください。ClientResetRequiredErrorクラスはその時点でのローカルのRealmデータベースの情報や、新たにサーバーからバックアップ時点のデータを取得し直すためのメソッドを提供しています。

もし直ちに”client reset”に対応しない場合は、次回のアプリ起動後の最初のデータベースアクセスの際に自動的にローカルのデータベースが削除され、バックアップ時点のデータが再ダウンロードされます。

final SyncConfiguration config = new SyncConfiguration.Builder(user , url)
       .errorHandler(new SyncSession.ErrorHandler() {
           @Override
           public void onError(SyncSession session, ObjectServerError error) {
               if (error.getErrorCode() == ErrorCode.CLIENT_RESET) {
                   ClientResetRequiredError err = (ClientResetRequiredError) error;
                   closeRealm();
                   err.executeClientReset(); // Manually do the reset
                   err.getBackupFile(); // Reference to backed up file
               } else {
                   // Handle other errors
               }
           }
       })
       .build();

逆方向の関連(BETA)

Realmの提供する関連は、双方向のものです。つまり、PersonからDogへの関連をもつ場合、Realmは自動的に反対方向の関連も作成され、自動的に更新が行われます。

通常、この逆方向の関連はモデルクラス上では隠蔽されています。Realm Java 3.1では、@LinkingObjectsアノテーションを導入することでこの逆方向の関連をモデル上で扱えるようにしました。

以下の手順により逆方向の関連を定義します。

型パラメーターに関連元となるオブジェクトのクラスを指定したRealmResults型のフィールドを追加します。フィールドはfinalであることが必要です。つぎに、そのフィールドに@LinkingObjectsアノテーションを付与します。このアノテーションには、関連元のクラスのどのフィールドの関連を使用するかを示すため、関連元クラスので関連フィールドの名前をパラメーターとして指定します。Realmは自動的にこのフィールドにRealmResultsオブジェクトをセットします。アンマネージドオブジェクトは逆方向の関連をサポートしません。

以下の例を見てください。

public class Person extends RealmObject {
   public String name;
   public int age;
   public Dog dog;
}  

public class Dog extends RealmObject {
   public String name;

   @LinkingObjects("dog")
   public final RealmResults<Person> owners = null;
}

// Use the inverse relationship 
Dog dog = realm.where(Dog.class).findFirst();
dog.owners.size(); // Find number of owners
dog.owners.first(); // Get a reference to the owner of the dog

逆方向の関連が真に威力を発揮するのはこの関連をクエリで利用できるようになってからです現時点ではまだ利用可能ではありませんが、次のリリースに含められるように準備を進めています

逆方向の関連を扱うクエリが未提供であるため、@LinkingObjectsアノテーションには@Betaアノテーションが付与されています。みなさんからのフィードバックをお待ちしています。

ファイルフォーマット変更

3.1では、Realmのデータベースファイルフォーマットが変更されています。以前のRealmファイルはオープンされる際に自動的にフォーマットの更新が行われます。新しいフォーマットのファイルは、以前のバージョンのクライアントアプリからはひらくことができなくなります。

完全な変更内容のリストは、CHANGELOGを参照してください。


お読みいただきありがとうございます。 Realmで素晴らしいアプリケーションを作りましょう!お困りの際はStack Overflow(日本語)Slack(日本語)Twitter(日本語)GitHub(英語)でご相談ください。