android Realm 优化

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 ++;
 
        }
	}
}

数据库升级存在的问题还是魔法值非常多,操作步繁琐,因此可以优化。

数据库统一升级优化

数据库统一升级流程图如下

android Realm 优化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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

上一篇:Shiro 基础认证实现


下一篇:学堂在线-程序设计基础-第六章