LoginSignup
69
59

More than 5 years have passed since last update.

Realmの簡単な使い方メモ

Last updated at Posted at 2016-04-09

Realmメモ

全くのRealm素人ですが、
Realmハンズオン (Android) #2に参加したので、覚えたことを書いていきます。
http://realm.connpass.com/event/28919/

このドキュメントがめちゃくちゃ詳しいです。
https://realm.io/jp/docs/java/latest/

サンプルとステップはこちらにあるようです。
https://github.com/zaki50/Realm-Hands-On2_android

準備

/build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0-alpha4'
        classpath 'io.realm:realm-gradle-plugin:0.88.3'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

app/build.gradle

apply plugin: 'com.android.application'
// androidの後である必要がある
apply plugin: 'realm-android'

Applicationクラスで利用準備する

初期化

カスタムのApplication#onCreate内

    @Override
    public void onCreate() {
        Realm.setDefaultConfiguration(new RealmConfiguration.Builder(this).build());
    }

マイグレーション(フィールドの追加などのバージョンアップ)

DynamicRealmという特殊なオブジェクトを利用して、フィールドを追加する
ここに詳しいものがあるみたい
https://realm.io/docs/java/latest/#migrations

    @Override
    public void onCreate() {
        super.onCreate();
        Realm.setDefaultConfiguration(buildRealmConfiguration());
    }

    private RealmConfiguration buildRealmConfiguration() {
        return new RealmConfiguration.Builder(this)
                .schemaVersion(1L)
                .migration(new RealmMigration() {
                    @Override
                    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
                        if (oldVersion == 0L) {
                            final RealmObjectSchema tweetSchema = realm.getSchema().get("Tweet");
                            tweetSchema.addField("favorited", boolean.class);
                            //noinspection UnusedAssignment
                            oldVersion++;
                        }
                    }
                })
                .build();
    }

エンティティの用意

RealmObjectを継承する。
プライマリーキーがある場合は@PrimaryKeyをつける。
StatusはTwitter4jのオブジェクトなので、各自入れたいものをコンストラクタで渡せば良い。

package io.realm.handson2.twitter.entity;
import java.util.Date;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import twitter4j.Status;
public class Tweet extends RealmObject {
    @PrimaryKey
    private long id;
    private Date createdAt;
    private String screenName;
    private String text;
    private String iconUrl;
    private boolean favorited;
    public Tweet() {
    }
    public Tweet(Status status) {
//https://dev.twitter.com/overview/api/twitter-ids-json-and-snowflake
        setId(status.getId());
        setCreatedAt(status.getCreatedAt());
        setScreenName(status.getUser().getScreenName());
        setText(status.getText());
        setIconUrl(status.getUser().getProfileImageURLHttps());
        setFavorited(status.isFavorited());
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public Date getCreatedAt() {
        return createdAt;
    }
    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
    public String getScreenName() {
        return screenName;
    }
    public void setScreenName(String screenName) {
        this.screenName = screenName;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public String getIconUrl() {
        return iconUrl;
    }
    public void setIconUrl(String iconUrl) {
        this.iconUrl = iconUrl;
    }
    public boolean isFavorited() {
        return favorited;
    }
    public void setFavorited(boolean favorited) {
        this.favorited = favorited;
    }
}

データを入れる

Realm.getDefaultInstance()した分だけ、realm.close();する必要がある。
executeTransaction()を使うことで楽にトランザクションできる。
copyToRealmOrUpdate()を使うと追加するかprimaryKeyによってアップデートするかうまくしてくれる。
copyToRealm()も存在し、これの場合は同じprimaryKeyを入れようとするとExceptionが投げられます。

        final Realm realm = Realm.getDefaultInstance();
        try {
            realm.executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    for (Status status : homeTimeline) {
                        final Tweet tweet = new Tweet(status);
                        // プライマリーキーが同じならアップデート
                        realm.copyToRealmOrUpdate(tweet);
                    }
                }
            });
        } finally {
            // getしたらcloseする
            realm.close();
        }

ちなみにハンズオンではデータ取得とデータを入れるのにIntentServiceを利用していました。

データを取り出して表示する

realm.allObjectsSorted(Tweet.class, "createdAt", Sort.DESCENDING);というように使うことでソートしたリストが取得できる。

realm = Realm.getDefaultInstance();
final RealmResults<Tweet> tweets = realm.allObjectsSorted(Tweet.class, "createdAt", Sort.DESCENDING);

データ変更時に自動的に更新する

RealmBaseAdapterを使うとRealmのデータが変更された時に自動的にnotifyDataSetChanged()が呼ばれて、いい感じにしてくれる。(RecyclerView用のものはこれから追加されるらしい。今はプルリクの状態:https://github.com/realm/realm-java/pull/2548 )
終了時にはrealm.close();する。(Androidのライフサイクルに合わせる)

public class TimelineFragment extends ListFragment {
    private Realm realm;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        realm = Realm.getDefaultInstance();
        final RealmResults<Tweet> tweets = buildTweetList(realm);
        final RealmBaseAdapter<Tweet> adapter = new RealmBaseAdapter<Tweet>(getContext(), tweets, true) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                final Tweet tweet = getItem(position);
                if (convertView == null) {
                    convertView = inflater.inflate(R.layout.listitem_tweet, parent, false);
                }
                                // TODO ViewHolderパターンを適用
                ((TextView) convertView.findViewById(R.id.screen_name)).setText(tweet.getScreenName());
                ((TextView) convertView.findViewById(R.id.text)).setText(tweet.getText());
                Glide.with(TimelineFragment.this).load(tweet.getIconUrl()).into((ImageView) convertView.findViewById(R.id.image));
                return convertView;
            }
        };
        setListAdapter(adapter);

    }

    @NonNull
    protected RealmResults<Tweet> buildTweetList(Realm realm) {
        return realm.allObjectsSorted(Tweet.class, "createdAt", Sort.DESCENDING);
    }


// 閉じる必要あり
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        // Fragmentのバグ?でDestroyされた後もViewがrealmをいじってしまう場合があるので、realmの結果を使わないように変更
        ((RealmBaseAdapter<?>) getListAdapter()).updateRealmResults(null);
        realm.close();
        realm = null;
    }

データを絞り込む

equalTo()を使うことで絞込ができるみたい

    @NonNull
    protected RealmResults<Tweet> buildTweetList(Realm realm) {
        return realm.where(Tweet.class)
                .equalTo("favorited", true)
                .findAllSorted("createdAt", Sort.DESCENDING);
    }

RxJavaと使う

(ハンズオンの内容にはありませんでしたが、、)
依存関係の追加

dependencies {
    compile 'io.reactivex:rxjava:1.1.3'
}

こんな感じでObservableが使えるみたい

realm.allObjectsSorted(Tweet.class, "createdAt", Sort.DESCENDING).asObservable();

まとめ

普通に使いやすそうなので、これに速さなどの利点があって、Rxに対応していたりして、とても良いのではないかと思いました。

69
59
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
69
59