#はじめに
Realmを使い始めてまだ間もない頃、copyToRealm()
の役割を理解しないままコードを書いていたせいで、バグを連発してしまいました。これは、そのときの自分に読ませたい記事です。
教訓: ManagedObjectとUnmanagedObjectの違いを理解してコードを書こう
Realmのオブジェクトには ManagedObject
と UnmanagedObject
の2パターンがあります。
これに関して、Realmの公式ドキュメント(Realm Java 5.9.1)には、次のような説明があります。
Instances of Realm objects can be either managed or unmanaged.
Managed objects are persisted in Realm, are always up to date and thread confined. They are generally more lightweight than the unmanaged version as they take up less space on the Java heap.
Unmanaged objects are just like ordinary Java objects, they are not persisted and they will not be updated automatically. They can be moved freely across threads.
It is possible to convert between the two states using Realm.copyToRealm and Realm.copyFromRealm.
上記をGoogle翻訳にかけたあと、微修正したものがこちらです。
Realmオブジェクトのインスタンスは、Managed(=管理対象)またはUnmanaged(=管理対象外)のどちらでも構いません。
ManagedObjectはRealmに永続化され、常に最新の状態に保たれ、スレッドは制限されます。これらはJavaヒープ上の占有スペースが少ないので、一般的にUnmanagedObjectよりも軽量です。
UnmanagedObjectは、通常のJavaオブジェクトとまったく同じです。永続化されていないため、自動的に更新されることはありません。 これらはスレッド間で自由に移動できます。
Realm.copyToRealmとRealm.copyFromRealmを使用することで、2つの状態を切り替えることができます。
ポイントは、
UnmanagedObject
の値は自動更新されないため、適宜Realm.copyToRealm()
を使う必要がある、ということです。
実装例: ToDoオブジェクトの保存 (2通り)
例えば、次のようなクラスをRealmで管理したいとします。
public class ToDo extends RealmObject{
// タイトル
public String title;
// 日付
public String updateDate;
// 内容
public String content;
// チェックボックスがチェックされているか
public boolean isChecked;
}
このToDoクラスのオブジェクトを最初に実装するときは、ManagedObject
と UnmanagedObject
のどちらでも構いません。
// ManagedObjectとして実装
ToDo todo = realm.createObject(ToDo.class);
// UnmanagedObjectとして実装
ToDo todo = new ToDo();
なぜなら、先ほどの公式ドキュメントの引用文中にもあったように、処理の途中でUnmanagedObject
をManagedObject
に変更したいときはRealm.copyToRealm()
を使うことで解決でき、ManagedObject
をUnmanagedObject
に変更したいときはRealm.copyFromRealm()
を使うことで解決できるからです。
ただし、大抵のRealm入門記事ではManagedObject
として実装されています。(自分調べ)
ToDoオブジェクトの保存メソッド
オブジェクトの持つ値を保存するときは、そのオブジェクトがManagedObject
なのか UnmanagedObject
なのかを区別して処理を書く必要があります。
例として、ToDoオブジェクトの保存メソッドsave()
を用意しました。
まずは、次の枠組みを見てください。
public void save(final String title, final String updateDate, final String content){
realm.executeTransaction(new Realm.Transaction(){
@Override
public void execute(Realm bgRealm){
// ここに、値を保存するための処理を書く。
}
});
}
この枠組みの中に、オブジェクトの状態に合わせた処理を書く必要があります。
ManagedObjectを保存するとき
ManagedObject
の値は自動で更新されるため、通常のJavaオブジェクトと同じような処理で構いません。
ToDo todo = realm.createObject(ToDo.class);
// 保存したい値を代入
todo.title = title;
todo.updateDate = updateDate;
todo.content = content;
UnmanagedObjectを保存するとき
UnmanagedObject
の値は自動で更新されないため、最後にRealm.copyToRealm()
を使う必要があります。
ToDo todo = new ToDo();
// 保存したい値を代入
todo.title = title;
todo.updateDate = updateDate;
todo.content = content;
// UnmanagedObjectからManagedObjectへと変更してRealmへコピー
realm.copyToRealm(todo);
一言まとめ
Realmを使うときは、オブジェクトがManaged
なのかUnmanaged
なのかに注意してコードを書きましょう。