LoginSignup
12
12

More than 5 years have passed since last update.

realm-java を使う際に Realm#close() を意識したくないので、ヘルパーライブラリを作った

Posted at

以前ちらっと書いた、モデル中心の設計をするために、最近は本業のほうでも趣味の方でも、 realm-java をヘビーユースしています。

まえおき: Realmって関連モデル扱うとき本当に便利だよ!

SQLだと、 User has_many Message みたいなのを扱うとき、ちょいちょい面倒だったんですが、Realmだと

class User extends RealmObject {
  @PrimaryKey
  private long id;
  private String name;
}

class Message extends RealmObject {
  @PrimaryKey
  private long id;
  private String body;
  private User sender;
}

みたいなモデルを定義しておけば

messages = [
 {
  id: 12,
  body: "お元気ですか",
  sender: {
   id: 1
  }
 },
 {
  id: 11,
  body: "こんにちは",
  sender: {
   id: 1
  }
 }
]

users = [
 {
  id: 1,
  name: "山田太郎"
 },
 {
  id: 2,
  name: "岩木祐輔"
 }
]

みたいなJSONを

JSONArray users = ... ;    //上記のJSON
JSONArray messages = ... ; //  〃

Realm.getDefaultInstance().executeTransaction(new RealmTransaction(
  public void execute(Realm realm) {
    realm.createOrUpdateAllFromJson(User.class, users);
    realm.createOrUpdateAllFromJson(Message.class, message);
  }
));

ってかんじで関連をそのまま突っ込めるし、取得の時もいちいちJOINとか考えずに

Realm.getDefaultInstance().where(Message.class).equalsTo("sender.id", 2).findAll();

で id=2(岩木祐輔) さんのメッセージを取れるし、めっちゃ便利〜♪ なんです。

まえおき2: Realmは使い終わったらclose()を呼ばないとイケナイ

データベースなんで当たり前といえば当たり前なんですが、使い終わったらお掃除をちゃんとしないと、リソースリークするようです。

(参考: http://ja.stackoverflow.com/questions/27862/android%E3%81%AErealm%E3%81%A7-io-realm-exceptions-realmerror-unrecoverable-error-too-many-op)

とはいえ・・・ close って忘れがちですよね。

というか、そもそも RealmTransactionなんていう素晴らしい仕組みがあるんだったら、Transaction抜けたらDBもcloseしてよー って思いません?(言い過ぎw

以前、SQLiteOpenHelper を使うときには、getReadableDatabase/getWritableDatabaseを直接使わない! っていう煽りっぽい記事かいたときにもちらっと書いてたんですが、個人的には、DBを使うスコープはPythonのwith構文みたいに明示的にスコープであって欲しい(open/close なんていちいち呼びたくない) という衝動から、すごく雑ですが、ライブラリを作るに至りました。

本題: realm-java-helpers。これでもう close忘れは起こさない

DBからReadするとき

RealmHelper.executeTransactionForRead(new RealmTransaction() {
  public void execute(Realm realm) {
    List<Message> messages = realm.where(Message.class).equalsTo("sender.id", 2).findAll();

    /* 
      ... messagesを使っていろいろ ...
     */

  }
}); // このRealmTransactionを抜けたら勝手にRealm#closeされるので、リソースリークはしない

DBにWriteするとき

RealmHelper.rxExecuteTransactionAsync(new RealmTransaction() {
  public void execute(Realm realm) {
    /* 
      ... realm にいろいろ書く ...
     */
  }
}).subscribe(new Action1<Void>(){
  public void call(Void xx) {
    Log.d(TAG, "Successfully saved!");
  }
}) // このsubscriptionを抜けたら勝手にRealm#closeされるので、リソースリークはしない

みたいな感じです。

未解決なところ

realm-android-adapters と組むときに、うまくScopedな感じでAdapterが使えるようにはなっていない。
ActivityとかFragmentみたいなライフサイクルをもった子たちに、イイカンジにRealmスコープをインジェクションできる仕組みってないかなぁ・・・ないよなぁ・・・ ということで、未解決です。

realm-java-helpers ぜひ使ってフィードバックください!

気になる点などは GitHub issueでおねがいします!

12
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12