公司的项目一直都是使用的ActiveAndroid,这是一个很传统的ORM框架,不过无论是与Gson的配合使用,还是连接查询或者分页查询,传统数据库的理念它都能支持的很好。无奈的是这个项目在GitHub上的最近更新时间还是在两年前,它对AndroidStudio的InstantRun特性支持的不是很好(编译时间就是程序员的生命啊,感谢Google推出的这一神器 )。强行使用的话可能会报如下错误:
第二点是它的版本升级策略做的不好,不能做到跨版本升级,目前的做法只能是升级APP的后如果检测到先前的版本就卸载然后重装,原先的数据只能丢失了。这样简单粗暴的做法自然不是长久之计。
第三点是不能查询个别列,将所有字段都查出来既浪费时间,又浪费空间。
ActiveAndroid的罪过数落完了,自然要把更换数据库的Task提上日程。leader给新的数据库提了五点要求:
最难的一点是更换只能在Service层进行(项目中所有的数据库操作都是通过一个一个Service完成的),不能对项目进行大量修改这一限制,注定了使用Realm会遇到一个又一个的坑。
Realm确实是一个非常前沿的数据库框架,跟其它ORM的千遍一律不同,它提供了强大的功能和可靠的速度,它的优点可以作如下总结:
public static Realm getDefaultInstance() {
if (defaultConfiguration == null) {
throw new NullPointerException("No default RealmConfiguration was found. Call setDefaultConfiguration() first");
}
return RealmCache.createRealmOrGetFromCache(defaultConfiguration, Realm.class);
}
这里可以看到,每个线程只能拥有一个Realm实例,再点进createRealmOrGetFromCache():
static synchronized <E extends BaseRealm> E createRealmOrGetFromCache(RealmConfiguration configuration,Class<E> realmClass) {
······
//这个类保存了Realm 和当前线程使用getInstance()的计数器,以及全局计数器。
RefAndCount refAndCount = cache.refAndCountMap.get(RealmCacheType.valueOf(realmClass));
if (refAndCount.localRealm.get() == null) {
// Create a new local Realm instance
BaseRealm realm;
if (realmClass == Realm.class) {
// RealmMigrationNeededException might be thrown here.
//在这里创建了新对象
realm = Realm.createInstance(configuration, cache.typedColumnIndices);
} else if (realmClass == DynamicRealm.class) {
realm = DynamicRealm.createInstance(configuration);
} else {
throw new IllegalArgumentException(WRONG_REALM_CLASS_MESSAGE);
}
// The cache is not in the map yet. Add it to the map after the Realm instance created successfully.
if (!isCacheInMap) {
cachesMap.put(configuration.getPath(), cache);
}
//创建一个Realm实例后,保存并将计数器置零。
refAndCount.localRealm.set(realm);
refAndCount.localCount.set(0);
}
Integer refCount = refAndCount.localCount.get();
if (refCount == 0) {
...
//全局计数器加1
refAndCount.globalCount++;
}
//线程计数器加1
refAndCount.localCount.set(refCount + 1);
@SuppressWarnings("unchecked")
E realm = (E) refAndCount.localRealm.get();
return realm;
所以在一个线程中可以多次使用getInstance(),并不会影响性能,但是从close() 方法的源码来看,调用一次close(),也只是将计数器减一,只有计数器归零,才会执行回收工作。也就是说,同一线程,用了几次getInstance 就要调几次 close ,否则就会内存泄漏,而且泄漏的是c++底层的那部分,这设计的就比较尴尬了。
接着走,刚才看到,对于第一次调用getInstance,会调用createInstance, 那跳进这个方法看看:
static Realm createInstance(RealmConfiguration configuration, ColumnIndices columnIndices) {
try {
return createAndValidate(configuration, columnIndices);
} catch (RealmMigrationNeededException e) {
if (configuration.shouldDeleteRealmIfMigrationNeeded()) {
deleteRealm(configuration);
} else {
try {
migrateRealm(configuration);
} catch (FileNotFoundException fileNotFoundException) {
// Should never happen
throw new RealmIOException(fileNotFoundException);
}
}
return createAndValidate(configuration, columnIndices);
}
}
并没有什么有用的信息,只是抛出版本不匹配异常时,会根据flag删除或更新以前的Realm,关键还是createAndValidate() :
static Realm createAndValidate(RealmConfiguration configuration, ColumnIndices columnIndices) {
Realm realm = new Realm(configuration);
...
return realm;
}
只需要关注这两句,调用了Realm的构造函数,而它的构造函数什么都没做,只是调用了它的父类BaseRealm的构造:
protected BaseRealm(RealmConfiguration configuration) {
//终于发现了线程相关的东西和AutoRefresh
this.threadId = Thread.currentThread().getId();
...
//handlerController 就是Handler.Callback
this.handlerController = new HandlerController(this);
if (handlerController.isAutoRefreshAvailable()) {
setAutoRefresh(true);
}
}
public void setAutoRefresh(boolean autoRefresh) {
checkIfValid();
handlerController.checkCanBeAutoRefreshed();
if (autoRefresh && !handlerController.isAutoRefreshEnabled()) { // Switch it on
//这里创建了Handler,与当前线程绑定到了一起。而AutoRefresh就是在handlerController中实现的。
handler = new Handler(handlerController);
handlers.put(handler, configuration.getPath());
} else if (!autoRefresh && handlerController.isAutoRefreshEnabled() && handler != null) { // Switch it off
removeHandler();
}
handlerController.setAutoRefresh(autoRefresh);
}
至此,源码的探究应该告一段落了,接着列举一些Realm的特点:
总之,一个项目若是处于设计初期,我觉得使用Realm还是很方便的,毕竟,老技术虽然稳定,但总会有各种无法解决的缺陷,而新技术,正是为了解决这些缺陷而来的。
2025 - 快车库 - 我的知识库 重庆启连科技有限公司 渝ICP备16002641号-10
企客连连 表单助手 企服开发 榜单123