User
User

Reputation: 1236

Right way of doing Realm Migration Android

We use Realm for our app. Our app has been beta released. Now I want to add a field to one of our realm objects. So I got to write RealmMigration and I wrote one too. The Question here is how to apply this Realm migration to my app. I use Realm.getInstance() get the realm instance whenever I want to something. Remember, Realm.getInstance() is being used in the entire app everytime, I want to access Realm database.

So, I am bit Queried on how to apply this migration? Any leads can be helpful. Thanks.

My RealmMigration is as follows.

public class RealmMigrationClass implements RealmMigration {
    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        if(oldVersion == 0) {
            RealmSchema sessionSchema = realm.getSchema();

            if(oldVersion == 0) {
                RealmObjectSchema sessionObjSchema = sessionSchema.get("Session");
                sessionObjSchema.addField("isSessionRecordingUploading", boolean.class, FieldAttribute.REQUIRED)
                        .transform(new RealmObjectSchema.Function() {
                            @Override
                            public void apply(DynamicRealmObject obj) {
                                obj.set("isSessionRecordingUploading", false);
                            }
                        });


                sessionObjSchema.setNullable("isSessionRecordingUploading",false);
                oldVersion++;
            }

        }
    }

}

public class Session extends RealmObject {

    @PrimaryKey
    private String id;
    @Required
    private Date date;
    private double latitude;
    private double longitude;
    private String location;
    private String note;
    private String appVersion;
    private String appType;
    private String deviceModel;
    private HeartRecording heart;
    private TemperatureRecording temperature;
    private LungsRecording lungs;
    @NotNull
    private boolean isSessionRecordingUploading;
    private boolean sessionInfoUploaded;
    private boolean lungsRecordingUploaded;
    private boolean heartRecordingUploaded;

}

Removed Getter and Setters from RealmObject to cut short the Question. The exception occurred when I try to reinstall the app without uninstalling the previous one. Please advice.

Upvotes: 30

Views: 35030

Answers (2)

Christian Melchior
Christian Melchior

Reputation: 20126

It is described here: https://realm.io/docs/java/latest/#migrations

But in essence, you just bump the schema version and set the configuration like this:

RealmConfiguration config = new RealmConfiguration.Builder(context)
    .schemaVersion(2) // Must be bumped when the schema changes
    .migration(new MyMigration()) // Migration to run
    .build();

Realm.setDefaultConfiguration(config);

// This will automatically trigger the migration if needed
Realm realm = Realm.getDefaultInstance();

Upvotes: 40

Renato Probst
Renato Probst

Reputation: 6054

This is a helper class i have made to import a .realm database to my application. In my case i just need to read the db created from an iOS application in an Android application

public class RealmImporter {
private Activity activity;
private String dbaFullName = "db.realm";
private int rawRealmResource = R.raw.dbRealmResource;


public RealmImporter (Activity activity) {
    this.activity = activity;
    importData();
}


private RealmConfiguration getConfiguration() {
    RealmConfiguration config = new RealmConfiguration.Builder()
            .name(dbaFullName)
            .modules(new MyRealmModule())
            .migration(new RealmMigration() {
                @Override
                public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {

                }
            })
            .build();

    return config;
}

public Realm getInstance() {
    Realm realm = Realm.getInstance(getConfiguration());

    return realm;
}

private void importData() {
    copyBundledRealmFile(activity.getResources().openRawResource(rawRealmResource), dbaFullName);

    Realm.init(activity);
}

private String copyBundledRealmFile(InputStream inputStream, String outFileName) {
    try {
        File file = new File(activity.getFilesDir(), outFileName);
        if (file.exists()) {
            return file.getAbsolutePath();
        }
        FileOutputStream outputStream = new FileOutputStream(file);
        byte[] buf = new byte[1024];
        int bytesRead;

        while ((bytesRead = inputStream.read(buf)) > 0) {
            outputStream.write(buf, 0, bytesRead);
        }

        outputStream.close();
        return file.getAbsolutePath();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}


// Create the module
@RealmModule(classes = { Artigo.class, Comparativo.class, Indice.class, ItemDeArtigo.class})
public static class MyRealmModule{
}
}

If you have more than one realm configuration (if you need to import more than one .realm file) you need to create a RealmModule class and use the .modules() option on the RealmConfiguration.Builder .

This is needed because by default realm try to check if your .realm has tables for all your models that extend RealmObject, and if you have multiple .realm, each one of them will have some of your classes (but not all of them).

Another usefull information is that for swift to android migrations. All String properties must be declared with @Required anototation (if they have a default value).

If realm is giving you a strange Exception like "this class was not found in this schema", try to re run you app, usually it gives a different error which can hint to the real problem although sometimes it just gives a random error.

Upvotes: 1

Related Questions