扱いづらい点を書いてはいますが、概ねRealmは便利です。
前提として、主に単純なDBとしてRealmを使う場合に扱いづらいと感じたことです。
特にSwift版に比べると扱いづらい印象です。
単体テストがJVMだけで完結できない
Realmがandroidに依存しているので、AndroidTestで実行しないといけないです。
そういう時はRobolectricを使えばいいのですが、まだRealmには対応していないようです。
すなわち、実行に時間がかかるので、テストを気楽にできないのです。
もちろん、PowerMockで動作させることはできますが、Daoをターゲットにしたテストでrealmにinsert,update,selectが正しく動作しているかを検証したいのです。
(Dao以外のレイヤーでは、Daoはモック化するので問題ないです。)
公式のサンプルでは、やはりPowerMockを利用しています。
現状、根本的な解決策はなく、mockで正しくメソッドを呼んでいるかどうかのテストしかできないと思われます。
close後にアクセスするとクラッシュする
リソースを開いたら閉じるのは当然なのですが、entityに入れたつもりでプロパティにアクセスするとクラッシュ(This Realm instance has already been closed
)します。
Java Realmはリソースを閉じた後にアクセスできない仕様です。
それを避けるために、トランザクション内で全てを処理する必要がります。
Daoだけで完結させたい場合は、以下のようにrealm管理外のインスタンスにコピーする必要があります。
fun find(): AuthEntity? {
var result: AuthEntity? = null
Realm.getDefaultInstance().use { realm ->
val entity = realm.where(AuthEntity::class.java).findFirst()
if (entity != null) {
result = realm.copyFromRealm(entity)
}
}
return result
}
RealmはonCreate()
でインスタンスして、onDestroy()
でcloseする構成にするのが一般的(公式のドキュメントでも、「onDestory()
でclose」と記載されている)のようです。
しかし、ActivityにDao要素を依存させたくないし、例えば、MVVMでもViewModelをRealmに依存させたくないでしょう。なので、Realmをラップしたクラスを作り依存性を無くす実装をするかと思います。
が、単純な取得処理でもRealmに依存させずにトランザクションを意識するのは大袈裟です。
そこで上記のようなコードを書くという判断/解決策もありかなと思います。ただ、この処理はメモリや処理時間にコストがかかるようです。
EntityにPublicデフォルトコンストラクタが必要
Kotlinで利用する場合では、この制約のために引数にデフォルト値を入れないといけません。
kotlin-noarg Pluginを利用すれば、デフォルトコンストラクタを自動生成してくれるのですが、Realmの場合は、事前検証で弾いてしまっているためにビルドができませんでした。
該当のソース箇所です。
なのでデフォルト値が必要なくても、こういったクラスを書くことになります。
@RealmClass
data class SampleEntity(
@PrimaryKey
@SerializedName("id")
var id: Int = 0,
@SerializedName("sample")
var sample: String = ""
) : RealmModel