【问题标题】:Upgrade realm in an Android project在 Android 项目中升级领域
【发布时间】:2016-10-11 05:56:23
【问题描述】:

我目前在我的一个 Android 项目中运行 Realm 版本 0.82.0。我有一段时间没有接触 Realm,直到我最近注意到它们同时升级到了 2.0.2 版本。我想升级我的 Realm 版本,不幸的是,我不知道从旧版本升级到当前版本是否会正常工作或破坏我的代码。

我特别关心迁移,因为自从我编写代码以来,用于迁移的 API 似乎发生了一些变化,而且我不确定如果我只是更新我的版本,我的迁移是否会中断。不幸的是,他们的网页上没有关于升级 Realm 版本的文档。

有没有人有升级 Realm 的经验,尤其是两个主要版本的版本增加?

【问题讨论】:

  • 老实说,如果你能负担得起deleteIfMigrationNeeded(),这是最简单的。迁移 API 发生了巨大变化,例如,Table 不再可访问。虽然最大的变化发生在 0.89.0。
  • 只是出于好奇-您为什么突然决定升级它?我的意思是 - 如果是修复了一些错误或您需要一些功能,那么您真的别无选择。最近我从 SnappyDB 过渡到 Realm(snappy 似乎有一些莫名其妙的 db read 错误),并且过程还不错。所以我猜从旧版本升级更简单。
  • @Dev-iL 伙计,我记得从 0.88.3 升级到 0.89.0。那个开关有痛苦。 XD
  • @EpicPandaForce 没有痛苦 - 没有收获。 ;)
  • 我仍在决定是否升级,但根据文档,他们似乎在一些线程和空间管理问题上有所改进,这给我带来了一些困难,所以我认为它可能是切换到更新的版本是个好主意。不过deleteIfMigrationNeeded()肯定不行,所以如果没有其他可行的解决方案,我可能需要坚持旧版本

标签: android realm


【解决方案1】:

重大更改列表可在其 Github 上的 CHANGELOG.MD 中找到。

但是,值得注意的是,在开发过程中发生了很多重大变化,尤其是 0.89.0。

0.82.05.1.0如下(目前最稳定的版本):

0.82.0

重大更改:带有注释 @PrimaryKey 的字段现在会自动编入索引。旧架构需要迁移。

(0.82.2 在这里是最稳定的,但它在 Blackberry 设备上不起作用。在 Blackberry 上使用的第一个 stable 版本是 0.87.2。)

在 0.86.0+ 中,您可以使用

向带注释的字段添加索引
@Override
public void migrate(final DynamicRealm realm, long oldVersion, long newVersion) {
    RealmSchema schema = realm.getSchema();
    // version check and stuff
    RealmObjectSchema personSchema = schema.get("Person");
    personSchema.addIndex("fieldName");

0.83

重大更改:数据库文件格式更新。此版本创建的Realm文件不能被之前版本的Realm使用。

重大变化:从 Realm 类中删除了不推荐使用的方法和构造函数。

重大变化:引入了盒装类型 Boolean、Byte、Short、Integer、Long、Float 和 Double。添加了空支持。引入注解 @Required 以指示字段不可为空。默认情况下,String、Date 和 byte[] 可以为空,这意味着如果打开以前版本的 Realm 文件,将引发 RealmMigrationNeededException。

哦,男孩,这是一个不错的选择。 NULL 支持。

原语的盒装类型变得可用。默认情况下,盒装类型可以为空。所有StringDatebyte[] 都必须使用@Requiredschema.setNullable("fieldName", nullability) 进行注释,并使它们都可以为空。

0.84.0:

添加了异步查询。就架构而言,这里没有什么新东西。

0.85.0:

重大更改:删除 RealmEncryptionNotSupportedException,因为 Realm 的底层存储引擎中的加密实现发生了变化。现在所有设备都支持加密。

重大更改:Realm.executeTransaction() 现在直接抛出任何 RuntimeException 而不是将其包装在 RealmException (#1682) 中。

重大更改:如果字段名是链接字段且最后一个元素是链接,则 RealmQuery.isNull() 和 RealmQuery.isNotNull() 现在会抛出 IllegalArgumentException 而不是 RealmError (#1693)。

这里还没有什么重要的,虽然:

如果值包含无效(非托管、删除、关闭、来自不同领域)对象 (#1749),RealmObject 和 RealmList 的托管对象中的设置器现在会抛出 IllegalArgumentException。

这个很有趣。以前它只是失败了,所以这是最好的。但这也是 Realm 最大的限制。

0.86.0

重大更改:迁移 API 已被新 API 替换。

重大更改:RealmResults.SORT_ORDER_ASCENDING 和 RealmResults.SORT_ORDER_DESCENDING 常量已替换为 Sort.ASCENDING 和 Sort.DESCENDING 枚举。

重大更改:RealmQuery.CASE_SENSITIVE 和 RealmQuery.CASE_INSENSITIVE 常量已替换为 Case.SENSITIVE 和 Case.INSENSITIVE 枚举。

重大更改:Realm.addChangeListener、RealmObject.addChangeListener 和 RealmResults.addChangeListener 持有对侦听器的强引用,您应该注销侦听器以避免内存泄漏。

重大更改:删除了已弃用的方法 RealmQuery.minimum{Int,Float,Double}、RealmQuery.maximum{Int,Float,Double}、RealmQuery.sum{Int,Float,Double} 和 RealmQuery.average{Int,Float,双倍的}。请改用 RealmQuery.min()、RealmQuery.max()、RealmQuery.sum() 和 RealmQuery.average()。

重大更改:删除了错误公开的 RealmConfiguration.getSchemaMediator()。并添加 RealmConfiguration.getRealmObjectClasses() 作为替代方法,以获取模型类集 (#1797)。

重大更改:Realm.addChangeListener、RealmObject.addChangeListener 和 RealmResults.addChangeListener 在非 Looper 线程上调用时会抛出 IllegalStateException。这是为了防止注册不会被调用的监听器。

使用 DynamicRealm 和 DynamicRealmObject 添加了新的动态 API。

添加了 Realm.getSchema() 和 DynamicRealm.getSchema()。

new Migration API, using DynamicRealm instead of Realm.getTable()

有些东西被重命名了,如果你的结果集仍然有效,你应该取消注册你的更改监听器。但值得注意的是,您仍然应该为您的RealmResults 保留一个字段变量,因为Realm 的Context 对它只有一个弱引用。

0.87.0

RX 支持。没什么重要的。

0.87.2

在提交事务时移除显式 GC 调用 (#1925)。

终于,Realm 又稳定了! :)

0.88.0

重大变化

Realm 现在必须作为 Gradle 插件安装。

DynamicRealm.executeTransaction() 现在直接抛出任何 RuntimeException 而不是将其包装在 RealmException 中 (#1682)。

DynamicRealm.executeTransaction() 现在会抛出 IllegalArgumentException 而不是静默接受 null Transaction 对象。

对于无效代理,字符串设置器现在抛出 IllegalArgumentException 而不是 RealmError。

DynamicRealm.distinct()/distinctAsync() 和 Realm.distinct()/distinctAsync() 现在针对无效类型或未索引字段抛出 IllegalArgumentException 而不是 UnsupportedOperationException。

所有线程本地更改侦听器现在都延迟到下一个 Looper 事件,而不是在提交时被触发。

从 0.86.0 中已弃用的公共 API 中删除了 RealmConfiguration.getSchemaMediator()。请使用 RealmConfiguration.getRealmObjectClasses() 获取模型类集(#1797)。

如果 Realm 文件不存在,Realm.migrateRealm() 会抛出 FileNotFoundException。

现在需要取消订阅所有 Realm RxJava observables 才能完全关闭 Realm (#2357)。

很好。现在是 AAR。您必须添加到 classpath 并使用 apply plugin: 'realm-android' 而不是 compile ... 依赖项运行它。

仅在下一个事件循环时调用更改侦听器,而不是在提交后立即调用。我.. 老实说,我并不完全确定这会产生什么后果,但这意味着更改侦听器不适用于后台线程。仅在 Looper 线程(主要是 UI 线程)上。

增强功能

支持自定义方法、访问器中的自定义逻辑、自定义访问器名称、接口实现和 Realm 对象中的公共字段 (#909)。

使用 ReLinker 改进了 .so 加载。

虽然这是非常必要的,所以我肯定不想卡在 0.87.5 上。

0.89.0:

重大变化

@PrimaryKey 字段值现在可以为 String、Byte、Short、Integer 和 Long 类型的 null。应该使用 RealmObjectSchema.setNullable() 或通过添加 @Required 注释来迁移较旧的领域。 (#2515)。

RealmResults.clear() 现在抛出 UnsupportedOperationException。请改用 RealmResults.deleteAllFromRealm()。

RealmResults.remove(int) 现在抛出 UnsupportedOperationException。请改用 RealmResults.deleteFromRealm(int)。

RealmResults.sort() 和 RealmList.sort() 现在返回排序后的结果,而不是就地排序。

如果 RealmList 为空,RealmList.first() 和 RealmList.last() 现在会抛出 ArrayIndexOutOfBoundsException。

从公共 API 中删除了已弃用的方法 Realm.getTable()。

Looper 上的 Realm.refresh() 和 DynamicRealm.refresh() 不再有任何效果。 RealmObject 和 RealmResults 总是在下一个事件循环中更新。

好吧,这个是最乱的一个。

1.) 您必须为@PrimaryKey 注释字段添加@Required 注释,因为null 是有效的主键值。

2.) realm.refresh() 不再有效。无论如何它都会被删除。不过,这里有一个workaround for 1.1.1,应该只在后台线程上使用。不过,它在 Realm 3.2 中再次可用。

3.) getTable() 被删除。不要使用它。使用新的迁移 API。

4.) realmResults.sort() 返回一个新的 RealmResults,它也需要附加更改侦听器。我认为它不可靠,所以我只使用findAllSorted()

5.) 你可能不会想太多,但是

RealmObject 和 RealmResults 总是在下一个事件循环中更新。 (注意:这不再是真实的,因为 REALM 3.1+ 在 commitTransaction() 上再次调用更改侦听器

这实际上意味着 RealmResults 仅在事件循环发生时更新,而不是在您调用 realm.commitTransaction() 时立即更新。这也意味着在后台线程上,当您commitTransaction() 时,RealmResults 没有更新,您必须重新查询它们。

RealmResults 只有在调用附加的RealmChangeListener 后才会更新。在 1.1.1 中,当调用 RealmChangeListener 时,所有结果都已更新。

然而,这一变化也改变了事务中的迭代行为。在交易中,您总是看到最新版本。这意味着在您对其进行迭代和修改元素时,会重新评估查询。 (这也是 REALM 3.0 以来的情况

例如,以前这是有效的代码:

RealmResults<Stuff> stuffs = realm.where(Stuff.class).equalTo("something", false).findAll();
while(!stuffs.isEmpty()) {
    stuffs.get(0).setSomething(true);
}
// you end up here because stuffs will be empty 
// because of live auto-updates in transactions

但是,这将不再有效。对我来说,这会导致问题,因为我有时会这样迭代

RealmResults<Stuff> stuffs = realm.where(Stuff.class).equalTo("something", false).findAll();
for(int i = 0; i < stuffs.size(); i++) {
    stuffs.get(i--).setSomething(true);
}
// I end up here because of live auto-updates

这是一个问题,因为stuffs 将不再更改。我必须在我的代码中搜索 -- 并像这样修复所有迭代。

以前的官方解决方法是这样的:

RealmResults<Stuff> stuffs = realm.where(Stuff.class).equalTo("something", false).findAll();
for(int i = stuffs.size()-1; i >= 0; i--) {
    stuffs.get(i).setSomething(true);
}
// I end up here because of normal iteration

这在 0.89.0 中仍然可以正常工作。

从 0.89.0 开始,这也是有效代码(在 3.0.0+ 中,这会自动创建快照集合):

RealmResults<Stuff> stuffs = realm.where(Stuff.class).equalTo("something", false).findAll();
for(Stuff stuff : stuffs) {
    stuff.setSomething(true);
}

虽然结果中的元素仍然无效,但结果本身不会改变。 (在 Realm 3.0.0+ 中,快照集合也是如此)。

0.90.0:

重大变化

RealmChangeListener 也提供更改后的对象/领域/集合 (#1594)。

Realm 上的所有 JSON 方法现在只将 JSONException 包装在 RealmException 中。所有其他异常都按原样抛出。

将 RealmObject 上的所有方法和所有公共类标记为 final (#1594)。

从公共 API 中移除 BaseRealm。

从公共 API 中移除 HandlerController。

从公共 API (#1594) 中删除了 RealmAsyncTask 的构造函数。

RealmBaseAdapter 已移至其自己的 GitHub 存储库:https://github.com/realm/realm-android-adapters

Realm 文件的文件格式已更改。文件将自动升级,但无法使用旧版本的 Realm 打开 Realm 文件。

所以RealmBaseAdapter 现在在realm-android-adapters 中,对于Realm 的1.1.1,使用1.3.0。还添加了RealmRecyclerViewAdapter。对于3.5.0,请使用2.0.0 或更新版本。

RealmChangeListeners 有一个element 参数。耶。

此外,日期现在具有milisecond 精度。

0.91.0:

重大变化

删除了所有@Deprecated 方法。

即使 autoRefresh 为 false (#2820),从非 Looper 线程调用 Realm.setAutoRefresh() 或 DynamicRealm.setAutoRefresh() 也会引发 IllegalStateException。

在0.90.0中弃用了很多方法,所以

重大变化:

Realm.allObjects*()。请改用 Realm.where(clazz).findAll*()。

Realm.distinct*()。请改用 Realm.where(clazz).distinct*()。

DynamicRealm.allObjects*()。请改用 DynamicRealm.where(className).findAll*()。

DynamicRealm.distinct*()。请改用 DynamicRealm.where(className).distinct*()。

Realm.allObjectsSorted(字段,排序,字段,排序,字段,排序)。请改用 RealmQuery.findAllSorted(field[], sort[])`。

RealmQuery.findAllSorted(字段,排序,字段,排序,字段,排序)。请改用 RealmQuery.findAllSorted(field[], sort[])`。

RealmQuery.findAllSortedAsync(字段,排序,字段,排序,字段,排序)。请改用 RealmQuery.findAllSortedAsync(field[], sort[])`。

RealmConfiguration.setModules()。请改用 RealmConfiguration.modules()。

Realm.refresh() 和 DynamicRealm.refresh()。请改用 Realm.waitForChange()/stopWaitForChange() 或 DynamicRealm.waitForChange()/stopWaitForChange()。

waitForChange() 并没有像人们打算使用的那样真正起作用,所以这里有一个workaround for 1.1.1 to 3.1.4,但应该只在后台线程上使用。 refresh() 将在 3.2.0 中重新添加。

此外,在某些时候 Realm.getInstance(Context) 已被删除,请改用 Realm.getInstance(new RealmConfiguration.Builder(Context).build())


之后,1.0.0 来了,差不多就是这样。

顺便说一句,在 1.1.0 中,添加了 insertOrUpdate(),它比 copyToRealmOrUpdate() 更快,并且不返回代理。


2.0.2

  • 主键在托管对象上是不可变的,一旦设置,就无法更改,如果您尝试,它会引发异常。另外,如果您使用createObject() 创建对象,请使用realm.createObject(clazz, primaryKeyValue)

  • 您必须在某个时候致电Realm.init(Context)

  • 配置生成器不再接收上下文。

  • armeabi 不再受支持。 (仅 v7a 和其他)


在 3.0.0 之前没有重大更改,但有大量错误修复。


3.0.0:

RealmResults.distinct() 返回一个新的 RealmResults 对象,而不是对原始对象进行过滤 (#2947)。

RealmResults 会不断自动更新。当前线程上任何可能影响 RealmResults 的顺序或元素的事务都将立即更改 RealmResults,而不是在下一个事件循环中更改它。标准 RealmResults.iterator() 将继续正常工作,这意味着您仍然可以删除或修改元素而不会影响迭代器。对于简单的 for 循环,情况并非如此。在某些情况下,简单的 for 循环不起作用 (https://realm.io/docs/java/3.0.0/api/io/realm/OrderedRealmCollection.html#loops),您必须使用新的 createSnapshot() 方法。

RealmObject 上的 RealmChangeListener 现在也会在删除对象时触发。使用 RealmObject.isValid() 来检查这个状态(#3138)。 RealmObject.asObservable() 现在将在删除对象时发出该对象。使用 RealmObject.isValid() 来检查这个状态 (#3138)。

删除了已弃用的类 Logger 和 AndroidLogger (#4050)。

由于 Realm ObjectStore Results 集成,RealmResults 在事务中再次活动,就像在 0.88.3 及之前的版本一样。

所以simple for loops(使用for(int i = 0; ... 进行索引)很容易中断 - 这意味着您要么需要对它们进行反向迭代,要么先创建一个快照集合。

OrderedRealmCollection<Thing> snapshot = results.createSnapshot();
for(int i = 0; i < snapshot.size(); i++) { ...

此外,RealmObject 更改侦听器现在也会在删除时发出,您需要在更改侦听器中检查 isValid()。这样您就可以在后台删除对象时更新 UI。

3.1.0:

更新了 Realm 文件的文件格式。现有的 Realm 文件在打开时会自动迁移到新格式,但旧版本的 Realm 无法打开这些文件。

这里没什么可做的,但值得一提。

3.2.0-3.2.1:

这里没什么可做的,除了更新proguard,因为这里引入了一个bug。添加了 proguard 部分。

3.3.0:(和 3.3.1)

这里没什么可做的,修复了3.2.0中导致Proguard问题的bug。

3.4.0:

这里没什么可做的,尽管值得研究​​用于反向关系的新 @LinkingObjects API。

其实还是建议用单向链接+反向关系代替双向链接。

3.5.0:

重大变化

如果给定的 RealmModule 不包含所有必需的模型类 (#3398),则会引发 IllegalStateException。

如果您没有在modules() 中指定所有 RealmObjects(如果您使用多个模块而不是仅使用默认模块,例如库项目中的 RealmObjects),那么您需要确保您确实提供了所有 RealmObjects是模块中架构的一部分。

以前它会默默地添加它们,即使它们不在模块中,现在情况并非如此。

4.0.0:

重大变化

内部文件格式已升级。打开一个旧的领域 将自动升级文件,但旧版本的 Realm 会 不再能够读取该文件。

[ObjectServer] 将协议版本更新为仅兼容的 22 使用领域对象服务器 >= 2.0.0。

[ObjectServer] 已移除已弃用 API SyncUser.retrieveUser() 和 SyncUser.retrieveUserAsync()。采用 改为 SyncUser.retrieveInfoForUser() 和 retrieveInfoForUserAsync()。

[ObjectServer] SyncUser.Callback 现在接受通用参数 指示调用 onSuccess 时返回的对象类型。

[ObjectServer] 将 SyncUser.getAccessToken 重命名为 SyncUser.getRefreshToken。

[ObjectServer] 删除了不推荐使用的 API SyncUser.getManagementRealm()。

在排序后调用 distinct() RealmResults 不再清除任何已定义的排序 (#3503)。

放松 RealmList、RealmQuery、RealmResults 类型参数的上限, RealmCollection、OrderedRealmCollection 和 OrderedRealmCollectionSnapshot。

Realm 升级了对 RxJava1 的支持 到 RxJava2 (#3497) Realm.asObservable() 已重命名为 领域.asFlowable()。 RealmList.asObservable() 已重命名为 RealmList.asFlowable()。 RealmResults.asObservable() 已重命名 到 RealmResults.asFlowable()。 RealmObject.asObservable() 已 重命名为 RealmObject.asFlowable()。 RxObservableFactory 现在返回 RxJava2 类型而不是 RxJava1 类型。

删除了已弃用的 API RealmSchema.close() 和 RealmObjectSchema.close()。那些不必 不再被称为。

删除了已弃用的 API RealmResults.removeChangeListeners()。采用 RealmResults.removeAllChangeListeners() 代替。

已删除已弃用 API RealmObject.removeChangeListeners()。采用 RealmObject.removeAllChangeListeners() 代替。

已移除 UNSUPPORTED_TABLE、UNSUPPORTED_MIXED 和 UNSUPPORTED_DATE 从 领域字段类型。

删除了已弃用的 API RealmResults.distinct()/RealmResults.distinctAsync()。采用 改为 RealmQuery.distinct()/RealmQuery.distinctAsync()。

RealmQuery.createQuery(Realm, Class), RealmQuery.createDynamicQuery(DynamicRealm, String), RealmQuery.createQueryFromResult(RealmResults) 和 RealmQuery.createQueryFromList(RealmList) 已被删除。采用 Realm.where(Class)、DynamicRealm.where(String)、RealmResults.where() 和 RealmList.where() 代替。

所以 Rx1 支持被 Rx2 支持取代,removeChangeListeners() 被重命名为 removeAllChangeListeners()

大多数其他事情只会影响同步领域,从这一点开始,可以使用 RealmList&lt;String&gt;RealmList&lt;Date&gt;RealmList&lt;Integer&gt; 作为领域架构的一部分。暂不支持查询,create*FromJson方法不填写。

4.3.1:

已弃用

RealmQuery.findAllSorted() 和 RealmQuery.findAllSortedAsync() 支持谓词 RealmQuery.sort().findAll() 的变体。

支持 RealmQuery.distinct() 和 RealmQuery.distinctAsync() 变体 谓词 RealmQuery.distinctValues().findAll()

您现在可以使用 realm.where(Blah.class).distinct("something")realm.where(Blah.class).findAllSorted("something"),而不是使用

realm.where(Blah.class)
     .distinctValues("something") // subject to change to `distinct()` 
     .sort("something") // hopefully will change to `sorted()`? // nope, it's `sort`
     .findAll();

5.0.0:

将 RealmQuery.distinctValues() 重命名为 RealmQuery.distinct()

删除了以前弃用的 RealmQuery.findAllSorted()、RealmQuery.findAllSortedAsync() RealmQuery.distinct() 和 RealmQuery.distinctAsync()`。

OrderedRealmCollectionChangeListener.onChange() 中的 OrderedCollectionChangeSet 参数不再可以为空。请改用 changeSet.getState() (#5619)。

所以这意味着realm.where(...).findAllSorted("field") 应该是realm.where(...).sort("field").findAll()

还有 OrderedRealmCollectionChangeListener 曾经发送 null 作为初始更改集,现在不再是这种情况,== null 应该替换为 .getState() == OrderedCollectionChangeSet.State.INITIAL。这也意味着您需要在 Realm 5.0+ 中使用realm-android-adapters 3.0.0 或更新版本。

此外,如果您依赖于 __RealmProxy 类的名称:它们将以其完全限定名称命名,包括包,例如 my_package_SomeObjectRealmProxy


保护规则

#realm older than 0.84.1
-keepnames public class * extends io.realm.RealmObject
-keep @io.realm.annotations.RealmModule class *
-keep class io.realm.** { *; }
-dontwarn javax.**
-dontwarn io.realm.**

#realm 0.84.1+ and older than 1.0.0
-keep class io.realm.annotations.RealmModule
-keep @io.realm.annotations.RealmModule class *
-keep class io.realm.internal.Keep
-keep @io.realm.internal.Keep class *
-dontwarn javax.**
-dontwarn io.realm.**

#realm 0.89.0+ and older than 1.0.0
-keep class io.realm.RealmCollection
-keep class io.realm.OrderedRealmCollection 

#realm 3.2.0 and 3.2.1
-keepnames public class * extends io.realm.RealmObject

【讨论】:

  • 您是否有一个脚本来 grep 所有的重大更改?哇!格式不错!
  • 干得好,感谢您提供详尽的概述。我需要一些时间才能在家里尝试这个,而且我可能需要一些时间才能完成,所以当我完成时我会接受它。顺便说一句,我真的很喜欢你关于 Realm 的文章,非常简洁明了,真的很有帮助。继续努力
  • @EpicPandaForce:您能否解释一下 2.1.1 的关键问题,让您推荐 1.1.1?谢谢!
  • 2.0.0 通过“ObjectStore 集成”改变了很多内部逻辑,目前在一些旧的和低端设备(三星 Galaxy S3 Mini、三星 Galaxy Tab 3 , Blackberry) - 而 1.1.1 在所有设备上都非常稳定。在切换到 2.x 之前,我正在等待那些原生的怪癖得到修复。
【解决方案2】:

4+5+的Realm主要升级需要从:

realm.where(example.class)
    .findAllSorted("field")

收件人:

realm.where(example.class)
    .sort("field")
    .findAll();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多