Realm数据库优化
Realm数据的一个特点是支持跨平台操作,且效率上面比较高,是非关系数据库。但是在使用的过程中还是存在很多可以优化的控件,本文章重点解决Realm数据库无表信息和列信息,和Realm数据库统一升级的问题
Realm 数据库的使用
Android Studio中导入Realm依赖
在Realm数据库的官方文档中介绍,在Android中引入数据库只要两步。官方文档地址 [Install Realm - Android SDK — MongoDB Realm](https://docs.mongodb.com/realm/sdk/android/install/)
第一步,在项目的build.gradle中引入Realm插件。源码如下:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:3.5.1"
classpath "io.realm:realm-gradle-plugin:10.7.0"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
dependencies {
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
第二步,在Application的module中引入插件
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
以上两步,是最为简单的。同时官方提供了更为灵活的引入方案。方案如下
第一步,在Alpplication的build.gradle中引入Transform插件。源码如下:
buildscript {
ext.kotlin_version = '1.5.21'
ext.realm_version = '10.7.0'
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "io.realm:realm-transformer:$realm_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
// 在class 文件编译成dex 文件前对class文件进行操作
import io.realm.transformer.RealmTransformer
android.registerTransform(new RealmTransformer(project))
dependencies {
// realm 的注解库
api "io.realm:realm-annotations:$realm_version"
// realm 的核心库
api "io.realm:realm-android-library:$realm_version"
// realm kotlin的扩展库
api "io.realm:realm-android-kotlin-extensions:$realm_version"
// realm 的注解解析器
kapt "io.realm:realm-annotations-processor:$realm_version"
}
根据注解解析器的功能,可以根据自己的要求对注解解析器进行扩展满足自己的开发需求。
Realm 数据库生成相关列信息
根据官方文档,新建一个实体类只要如下源码就可以
@RealmClass
open class Student : RealmObject(){
@PrimaryKey
var id:Long? = UUID.randomUUID().mostSignificantBits
var name:String = ""
var sex:String? = null
}
R执行查询的相关操作是源码如下
val numTadpoles =
realm.where(Student::class.java).lessThan("id", 2).count()
这样的操作,会带来项目中有很多的魔法值,且当需要更改条件时,需要全局查找字符串,非常的麻烦,且无法在编译阶段就知道引用的列(field)数据是否是错的,需要在运行时才可以发现。因此根据GreenDao那样可以把列信息和表信息进行封装,这样可以更为方便的进行查询类操作。
通过观察源码发现,Realm会通过注解生成相关的类,源码如下:
public class com_kits_xrealm_bean_StudentRealmProxy extends com.kits.xrealm.bean.Student
implements RealmObjectProxy, com_kits_xrealm_bean_StudentRealmProxyInterface{
...
// 这里封装了表名
public static String getSimpleClassName() {
return "Student";
}
...
// 这里封装了所有的列相关的信息
private static OsObjectSchemaInfo createExpectedObjectSchemaInfo() {
OsObjectSchemaInfo.Builder builder = new OsObjectSchemaInfo.Builder(NO_ALIAS, "Student", false, 3, 0);
builder.addPersistedProperty(NO_ALIAS, "id", RealmFieldType.INTEGER, Property.PRIMARY_KEY, !Property.INDEXED, !Property.REQUIRED);
builder.addPersistedProperty(NO_ALIAS, "name", RealmFieldType.STRING, !Property.PRIMARY_KEY, !Property.INDEXED, Property.REQUIRED);
builder.addPersistedProperty(NO_ALIAS, "sex", RealmFieldType.STRING, !Property.PRIMARY_KEY, !Property.INDEXED, !Property.REQUIRED);
return builder.build();
}
}
根据以上的源码,可以扩展注解解析器生成源码
// 包名规则:在实体类的包名后添加 .build
package com.kits.xrealm.bean.build;
import io.realm.ITableDao;
import io.realm.RealmColumn;
import io.realm.RealmFieldType;
// 类名规则:在实体类后添加Dao
public class StudentDao implements ITableDao {
//表名
private static final String tableName = "Student";
private static final String NO_ALIAS = "";
public static final RealmColumn id;
public static final RealmColumn name;
public static final RealmColumn sex;
public static final RealmColumn[] columns;
public StudentDao() {
}
public String getTableName() {
return "Student";
}
public RealmColumn getColumnByName(String name) {
RealmColumn[] var2 = columns;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
RealmColumn column = var2[var4];
if (name.equals(column.alias()) || name.equals(column.name())) {
return column;
}
}
return null;
}
// 列信息
static {
id = new RealmColumn("", "id", RealmFieldType.INTEGER, true, false, false);
name = new RealmColumn("", "name", RealmFieldType.STRING, false, false, true);
sex = new RealmColumn("", "sex", RealmFieldType.STRING, false, false, false);
columns = new RealmColumn[]{id, name, sex};
}
}
查询类操作优化如下
val numTadpoles =
realm.where(Student::class.java).lessThan(StudentDao.id.name(), 2).count()
数据库统一生成优化
根据官方的文档介绍,数据库升级操作如下
public class MyMigration implements RealmMigration {
/**
* 本地数据库升级的时候会自动回调一次
* @param realm
* @param oldVersion
* @param newVersion
*/
@Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
Log.i("Realm",oldVersion + "-----" + newVersion);
RealmSchema schema=realm.getSchema();
if(oldVersion == 1 && newVersion ==2){
schema.get("VideoDownloadBean")
.addField("updateValue1", String.class)
.addField("updateValue2", String.class);
oldVersion ++;
}
}
}
数据库升级存在的问题还是魔法值非常多,操作步繁琐,因此可以优化。
数据库统一升级优化
数据库统一升级流程图如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nSXMAShy-1630580124310)(D:\电子书籍\总结文档\数据库统一升级.png)]
根据流程图参见源码 private fun migration(realm: DynamicRealm){...}
由于Realm中新增列,在原有的数据中为默认值为null,当需要给原有的数据进行数据设置默认值是需要调用接口 transform
。但是Realm没有相关注解实现此功能,因此新增注解,RealmExField
。代码示例如下
open class Teacher : RealmObject(){
// 这是新增的列,且需要修改默认初始值
@RealmExField(defValue = Test4DefVal::class)
private var test4: Float? = null
}
// 通过 defVal 返回默认初始值。
class Test4DefVal : InitDefVal<Float>{
override fun defVal(): Float {
return 123.23f
}
}
参考源码
相关源码可以参考git https://github.com/CodeKitBox/XRealm.git