LoginSignup
22
23

More than 5 years have passed since last update.

【Android】Realmを0.87.4から1.0.0にUpgradeしたときの備忘録

Last updated at Posted at 2016-06-02

Google様から古いOpenSSL使ってるアプリは2016/07/11以降、Playに公開/更新させないよというお達しもあり、Realmでは0.91.0未満では古いOpenSSLを使っているので、これを期に最新(1.0.0)にUpgradeしたときの備忘録です。
(古いOpenSSLでは脆弱性がありましたが、Realm内では脆弱性を含む機能を使用していないため、最近まで更新していなかったらしい)

本家のGetting Startedを参考に、0.87.4 => 1.0.0にUpgradeする際の手順です。(部分的にしか使ってなかったのでたぶん変更箇所は少ない方だと思います)
Change Logをみると結構たくさんBreaking changesがあるけど、頑張ろう!

手順

  • gradleで参照しているRealmのバージョンを更新
  • ビルドエラーを潰す
  • 実際に動かして、想定外の動きをする箇所を潰す

※基本的にはエラーや想定外の動作が出た箇所の実装をChange Log本家ドキュメントを見ながら変更/修正していくことの繰り返しです。

build.gradleの変更

projectレベルのbuild.gradleにdependenciesを追加(0.88.0/Breaking change)

build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:1.0.0"
    }
}

appレベルのbuild.gradleから0.87.4の記述を削除して1.0.0の記述を追記

app/build.gradle
apply plugin: 'realm-android'

dependencies {
  // compile 'io.realm:realm-android:0.87.4'
}

ビルドエラーの解消

リストAPI削除:RealmResults.removeLast()

メソッドのthrow追加:Realm.migrateRealm(RealmConfiguration configuration, RealmMigration migration)

  • FileNotFoundExceptionをthrowするようになった(0.88.0/Breaking change)
    • そもそもRealmConfiguration生成時にmigrationを設定する方法に変更してベストプラクティスに従ってRealm.getDefaultInstance()を使うよう変更

【変更前】

RealmUtil.java
public static Realm getInstance(Context context) {
    Realm realm;

    RealmConfiguration config = new RealmConfiguration.Builder(context)
            .schemaVersion(JmtyMigration.REALM_SCHEMA_VERSION)
            .build();
    try {
        realm = Realm.getInstance(config);
    } catch (RealmMigrationNeededException ex) {
        Realm.migrateRealm(config, new JmtyMigration());
        realm = Realm.getInstance(config);
    }

    return realm;
}

【変更後】

MyApplication.java
@Override
public void onCreate() {
    super.onCreate();
    sContext = getApplicationContext();

    // Realmセットアップ
    Realm.setDefaultConfiguration(RealmUtil.createRealmConfiguration(sContext));
}
RealmUtil.java
/**
 * RealmのConfigurationを生成する
 *
 * @param context
 * @return RealmConfiguration
 */
public static RealmConfiguration createRealmConfiguration(Context context){
    return new RealmConfiguration.Builder(context)
            .schemaVersion(JmtyMigration.REALM_SCHEMA_VERSION)
            .migration(new JmtyMigration())
            .build();
}

実際に動かして、想定外の動きをする箇所を潰す

ソート変更:RealmResults.sort()

  • エラーは出ず、ソートが効かなくなる
  • RealmResultsそのものへの操作ではなく、ソートしたオブジェクトを返却するようになった(0.89.0/Breaking changes

【変更前】

ArticleListFragment.java
Realm realm = Realm.getDefaultInstance();
RealmQuery<Article> query = realm.where(Article.class);
results = query.findAll();
results.sort("updatedAt", Sort.DESCENDING);

【変更後】

ArticleListFragment.java
Realm realm = Realm.getDefaultInstance();
RealmQuery<Article> query = realm.where(Article);
results = query.findAll().sort("updatedAt", Sort.DESCENDING);

String型のprimary keyを持ったRealmファイルが開けない

  • 以前のversionで作られたRealmファイルを参照しようとしたときにエラー
  • Primary Keyのフィールドがnullを許容する型(String, Byte, Short, Integer, and Long)だとRealmObjectSchema.setNullable()@Requiredのアノテーションを使わないとエラーになるようになった。
    • Schema versionを上げてRealmObjectSchema.isRequired(String)を実施(0.89.0/Breaking changes
      • nullを許容するならRealmObjectSchema.isNullable(String)を実施する(praimary keyでnull許容なんてケースあるのか?)
FATAL EXCEPTION: main
Process: com.snowmonkey.sample, PID: 8761
io.realm.exceptions.RealmMigrationNeededException: @PrimaryKey field '{フィールド名}' does not support null values in the existing Realm file. Migrate using RealmObjectSchema.setNullable(), or mark the field as @Required.
以下略

【変更前】

data/realm/Article.java
public class Article extends RealmObject {

    @PrimaryKey
    private String key;

    // 以下略
}

【変更後】

realm/data/Article.java
public class Article extends RealmObject {

    @PrimaryKey @Required
    private String key;

    // 以下略
}
realm/MyMigration.java
public class MyMigration implements RealmMigration {
    /** Current Schema Version. */
    public static final long REALM_SCHEMA_VERSION = 1;

    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        Log.d(getClass().getSimpleName(), "Migrate Realm Schema old[" + oldVersion + "] to new[" + newVersion + "]");
        if (oldVersion == 0) {
            // Migrate from v0 to v1
            migrate0To1(realm);
            oldVersion++;
        }

        if (oldVersion < newVersion) {
            throw new IllegalStateException(String.format("Migration missing from v%d to v%d", oldVersion, newVersion));
        }
    }

    /**
     * Migrate from version 0 to version 1.
     * At version 1, add @Required annotation for Primary Key(historyForShow) at SearchHistory Table.
     *
     * @param realm
     */
    private void migrate0To1(DynamicRealm realm) {
        RealmObjectSchema searchHistorySchema = realm.getSchema().get(SearchHistory.class.getSimpleName());
        searchHistorySchema.isRequired("key");
    }
}

所感的な何か

うちはまだそれほどがっつりRealm使っていなかったのでさくっと半人日もかからずUpgrade出来てよかったよかった。
というかちゃんと本家の更新を追ってないと差分が多くなって大変そうなので今後はチラチラ追っていこう。。。
(とはいえ「安定版の1.0.0になったから今後はBreaking changeは控える」って中の人が言ってたから大丈夫かな…?)

早くRealmConfiguration.Builder.assetFile()使ってアプリ初回起動時にやってたマスタデータ取得の時間を短縮したいぞおおおおおおお!!!

LGTM

22
23
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
22
23