library Project で使う Realm 3.1.0

はじめに

祝3.1.0 ですね〜。全然新機能は使えてないのですが<汗

またまた今回も zaki さんにRealmのSlackで不具合解析の相談をさせていただきました。

何時も感謝です〜><

一応念のため、備忘録として残しておこうかと*1

動作環境

  • macOS Sierra
  • 16G
  • HDDタイプのiMac
  • AS 2.3.1
  • Realm 3.1.0

状況的な話

下記のエラーがでて、copyOrUpdateRealm でエラーが出て保存されなくてハマってた。

Realm RealmObject is not part of the schema for this Realm

https://github.com/realm/realm-java/issues/3139

みたいな奴・・・・。まあ自分が使ってたのは RealmModelの方でしたが・・・

何故か OS6端末では動く/OS4、5では動かない という謎の状態・・。

一応アプリ消し手入れ直したりとかしてたんですけどね・・・

で zaki さんに相談したところ

APT変換で生成される*2自動生成コードのクラス判定分岐 が正常に生成されていないのでは?

とのお話でした

その時に、createOrUpdateAllFromJson の存在を教えてもらったんですけど、使ったことないなー(遠い目

githubでちょっと検索かけてみたけど、あんまり使ってるコードが見なかったかも・・

どのOSでも確実に動いたパターン

RealmInfoXXX は RealmModel を implements したクラス

@RealmClass 
public class RealmInfoA implements RealmModel

Library Projectのソース同梱タイプ

MainP
   |---RealmInfoA
LibP
   |---RealmInfoB
   |---RealmInfoC
   |---RealmInfoD
  • MainP/build.gradle
dependencies{
   compile project(':libP')
}

OS6でしか動かなかったパターン

LibPを make module LibP.aar にしたパターン *3

MainP
   |---RealmInfoA
LibP
   LibP.aar
     |---RealmInfoB
     |---RealmInfoC
     |---RealmInfoD

ASでlocal.jar を import するパターンですね・・

  • libP/build.gradle
configurations.maybeCreate("default")
artifacts.add("default", file('LibP.aar'))
  • MainP/build.gradle は変更なし

で何が悪かったのか?

LibP.aar にして固めてしまうと RealmInfoB とかが RealmPlugin の APT変換対象にならない

でどう解決するのか?

Sharing schemas を使う

LibP側

上記のページを参考にして下記のクラスを作ると

  • APT変換したコードが静的クラスとして生成
  • aarのclass.jar に io.realmパッケージ追加+RealmModelの変換済みのクラスが同梱される
  • 勿論staticクラスでもOK
   @RealmModule(library = true, allClasses = true)
   public static class MyLibraryModule {
   }
  • でコレをmoduleとして指定すると、クラス判定の条件分岐が増える
    • 正常にRealmModel/RealmObject 判定ができて正常実行できるようになる

MainP側

勿論LibP側において、MainPで利用する形でもOK

ただ setDefaultRealmConfiguration あたりはどうしても、本体側のApplication に記載する必要があるしな〜

変更前

.moduleは、変更前だと下記と同じ状況のようです

.modules(Realm.getDefaultModule())

public class RealmUtils {
    
    private static RealmConfiguration getRealmConfiguration(@NonNull String filename, int schemaVersion, RealmMigration migration) {
        RealmConfiguration.Builder builder = new RealmConfiguration.Builder()//context)
                    .name(filename)
                    .deleteRealmIfMigrationNeeded()
                    .schemaVersion(schemaVersion);

        if(migration != null){
            builder.migration(migration);
        }

        return builder.build();
    }
}

変更後

public class RealmUtils {
    
    //[TODO] aarのclass.jar に io.realmパッケージ追加+RealmModelの変換済みのクラスが同梱される
    @RealmModule(library = true, allClasses = true)
    public static class MyLibraryModule {
    }

    private static RealmConfiguration getRealmConfiguration(@NonNull String filename, int schemaVersion, RealmMigration migration) {
        RealmConfiguration.Builder builder = new RealmConfiguration.Builder()//context)
                    .name(filename)
                    .modules(Realm.getDefaultModule(), new MyLibraryModule()) //★ ココを追加
                    .deleteRealmIfMigrationNeeded()
                    .schemaVersion(schemaVersion);

        if(migration != null){
            builder.migration(migration);
        }

        return builder.build();
    }
}

OS6で何で動いたのか? あたりの調査

うーん。自動生成コードを見る限り動くはずがないんですよね・・・

RealmInfoAの分岐しか作られていないので。

何度も下記のオペレーションをしていたのですが・・・。

  • アプリ消去
  • データ消去
  • 端末再起動

ただ開発の常用端末なので、InstantRunのゴミが上記のオペレーションで消しきれていないのではないか 疑惑が有り。*4

だとすると、InstantRun 怖w って結論になってしまうのかなー

  • ただ AS2.4pの挙動見てると、
    • DebugモードはInstantRun必須*5

とかなりそうなので、それはそれでバギーな状況になりそう・・*6

*1:自分オッサンなので物忘れが激しいw

*2:Realm Pluginは内部でAnnotatioProcesser対応をしていて、aptのコード自動生成を利用している

*3:他のプロジェクトに持っていきやすくするためにpackしたイメージ。昔のapklibと同じようなもん

*4:試しに新規OS6のAVD作ったらエラー再現したので<汗

*5:CMakeがAS2.2で推奨だったのに、AS2.3では必須になってる

*6:近い将来、InstantRunを使わせない検証専用の端末が必要になる??