美文网首页Android技术知识Android开发经验谈Android开发
Android最好用的数据库框架——DBFLOW全面解析

Android最好用的数据库框架——DBFLOW全面解析

作者: 肖邦kaka | 来源:发表于2018-05-24 16:55 被阅读73次

    前言

    为什么说DBFLOW是最好用的数据库框架?因为它综合了各个数据库的框架的优点,它比GreenDao要使用简单,同时又比ActiveAndroid性能高很多,它是一款操作简单又高效的ORM框架。

    初始DBFLOW

    官方介绍

    根据官方介绍可以知道,DBFLOW是一个为Android设计的简单高效的数据库类库,它基于注解在编程过程中生成操作类,性能高效,操作安全。

    DBFLOW正确使用姿势

    DBFLOW配置(build.gradle版本3.0以下)

    引入apt和maven,配置在工程下gradle里面

      repositories {
        jcenter()
      }
      dependencies {
        classpath 'com.android.tools.build:gradle:2.0.0-beta6'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
      }
    }
    
    allprojects {
      repositories {
        jcenter()
        maven { url "https://jitpack.io" }
      }
    

    在app的gradle下配置apply plugin: 'com.neenbedankt.android-apt',同时导入依赖包

    apply plugin: 'com.android.application'
    apply plugin: 'com.neenbedankt.android-apt'
    def dbflow_version = "3.0.0-beta4"
    android {
      compileSdkVersion 23
      buildToolsVersion "23.0.2"
    
      defaultConfig {
        applicationId "cn.taoweiji.dbflowexample"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
      }
      buildTypes {
        release {
          minifyEnabled false
          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
      }
    }
    
    dependencies {
      compile fileTree(dir: 'libs', include: ['*.jar'])
      apt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}"
      compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}"
      compile "com.github.Raizlabs.DBFlow:dbflow:${dbflow_version}"
    }
    

    以上就是build.gradle版本3.0以下的DBFLOW的配置方式,基本上就是各种导包
    --------------------------------------分割线-----------------------------------------
    在Android Studio3.0以上版本、build.gradle版本3.0以上,已经把apt的注解方式修改为annotationProcessor,对应在配置也发生了变化,不需要再配置apt相关的设置
    build.gradle版本3.0以上DBFLOW相关配置
    工程下的gradle文件

    buildscript {
        
        repositories {
            google()
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.1.0'
    //        不需要配置apt
    //        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
            maven { url "https://www.jitpack.io" }
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    

    app下的gradle文件

    apply plugin: 'com.android.application'
    def dbflow_version = "4.2.1"
    android {
        compileSdkVersion 27
        defaultConfig {
            applicationId "com.kaka.dbflowdemo"
            minSdkVersion 18
            targetSdkVersion 27
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:27.1.1'
        implementation 'com.android.support.constraint:constraint-layout:1.1.0'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    
        annotationProcessor "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}"
        implementation "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}"
        implementation "com.github.Raizlabs.DBFlow:dbflow:${dbflow_version}"
        // sql-cipher database encyrption (optional)
        implementation "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${dbflow_version}"
    
    }
    

    建议使用annotationProcessor这种注解方法,不仅是配置简单,而且Android Studio对这种注解方式也进行了优化。

    初始化DBFLOW

    public class MyApp extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            //初始化DBFLOW
            FlowManager.init(this);
        }
    }
    

    别忘了在清单文件里面把application修改为当前Application

    创建数据库

    @Database(name = AppDataBase.NAME,version = AppDataBase.VERSION)
    public class AppDataBase {
        public static final String NAME="AppDataBase";
        public static final int VERSION=1;
    }
    

    创建一个类,需要声明一下数据库的NAME和VERSION,该@Database注释生成一个DatabaseDefinition现在引用名为“AppDatabase.db”的文件中的磁盘上的SQLite数据库。你可以在代码中引用它,DatabaseDefinition db = FlowManager.getDatabase(AppDatabase.class);

    创建表

    两种方式

    第一种(不推荐)

    @Table(database = AppDataBase.class)
    public class User {
        @PrimaryKey
        UUID id;
    
        @Column
        String name;
    
        @Column
        int age;
    }
    

    这种是最简单的方式,创建User类,通过注解来声明对应的数据库字段,@PrimaryKey是主键,@Column是字段的意思
    第二种(推荐)

    @Table(database = AppDataBase.class)
    public class User2Model extends BaseModel {
    
        @PrimaryKey(autoincrement = true)
        private int id;
    
        @Column
        private String name;
    
        @Column
        private int age;
    
        @Column
        private long timeStamp;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public long getTimeStamp() {
            return timeStamp;
        }
    
        public void setTimeStamp(long timeStamp) {
            this.timeStamp = timeStamp;
        }
    }
    

    使用这种方法创建表我们推荐,继承了BaseModel以后会更好更方便地让我们操作数据,代码更加简洁。
    注:不要重写构造方法,不要重写构造方法,不要重写构造方法;重要的事情说三遍。

    CRUD基本操作

    第一种创建表的方式的操作

            User user=new User();
            user.id= UUID.randomUUID();
            user.name="kaka";
            user.age=18;
            ModelAdapter<User> adapter=FlowManager.getModelAdapter(User.class);
            //插入User
            adapter.insert(user);
            //修改名字
            user.name = "Test";
            adapter.update(user);
            User userQuery=SQLite.select().from(User.class).querySingle();
            Log.e(TAG,"id="+userQuery.id+",name="+userQuery.name+",age="+userQuery.age);
    

    第二种创建表的方式

            User2Model userModel=new User2Model();
            userModel.setName("UserModel");
            userModel.setAge(new Random().nextInt(100));
            userModel.save();
            userModel.update();
            userModel.delete();
    

    从代码也可以看出第二种方式的代码更加简洁,打开BaseModel源码看一眼里面重写了getModelAdapter方法

    public ModelAdapter getModelAdapter() {
            if (modelAdapter == null) {
                modelAdapter = FlowManager.getModelAdapter(getClass());
            }
            return modelAdapter;
        }
    

    跟第一种实现的方式ModelAdapter<User> adapter=FlowManager.getModelAdapter(User.class);其实是一样的,只不过更简单一些。
    查询:
    DBFLOW在查询方法提高了很强大的支持,无论你是要排列、分组还是各种条件查询都可以满足

     List<User2Model> user2Models=SQLite.select().from(User2Model.class).where(User2Model_Table.age.greaterThan(18),User2Model_Table.name.eq("UserModel"))
                    .orderBy(OrderBy.fromNameAlias(NameAlias.of("id")))
                    .groupBy(NameAlias.of("id"))
                    .queryList();
            if (user2Models.size()!=0){
                for (User2Model user2Model:user2Models){
                    Log.e(TAG,"id="+user2Model.getId()+",name="+user2Model.getName()+",age="+user2Model.getAge());
                }
            }else{
                Toast.makeText(this,"数据为0",Toast.LENGTH_SHORT).show();
            }
    

    看到这样小伙伴们可能要问了User2Model_Table这个是个什么鬼,之前在对DBFLOW介绍的时候也说到了,DBFLOW是根据注解在编译过程生成对应的操作类,在你建好表(User2Model)以后,Make Project一下(或者ReBuild只要让代码重新编译一下)就会生成对应User2Model_Table操作类对象,这个XXX_Table操作对象在条件搜索过程都会被用到。

    事务操作、批量操作

    事务操作是我们数据库不得不去了结,DBFLOW当然也支持了事务的相关操作。

     FlowManager.getDatabase(AppDataBase.class).executeTransaction(new ITransaction() {
                @Override
                public void execute(DatabaseWrapper databaseWrapper) {
                    for (int i=0;i<100;i++){
                        User2Model userModel=new User2Model();
                        userModel.setName("UserModel");
                        userModel.setAge(new Random().nextInt(100));
                        userModel.save(databaseWrapper);
                    }
                }
            });
    

    这种是同步事务的方法,虽然DBFLOW执行的速度非常快,效率也很好,但是我们不推荐,因为当我们批量操作数据越来越大的时候,同步事务就会变成一个耗时的操作,而耗时操作我们要放在子线程里执行,这样就需要异步执行事务的方法

    //异步事务
            FlowManager.getDatabase(AppDataBase.class).beginTransactionAsync(new ITransaction() {
                @Override
                public void execute(DatabaseWrapper databaseWrapper) {
                    for (int i=0;i<100;i++){
                        User2Model userModel=new User2Model();
                        userModel.setName("UserModel");
                        userModel.setAge(new Random().nextInt(100));
                        userModel.save(databaseWrapper);
                    }
                }
            }).success(new Transaction.Success() {
                @Override
                public void onSuccess(@NonNull Transaction transaction) {
                    Log.e(TAG,"onSuccess()");
                }
            }).error(new Transaction.Error() {
                @Override
                public void onError(@NonNull Transaction transaction, @NonNull Throwable error) {
                    Log.e(TAG,"onError()");
                }
            }).build().execute();
    

    一波非常简洁的链式操作,并且提供好了事务操作成功和失败的回调

    数据库升级(增加表、修改表字段等)

    如果要增加表,除了要创建表以外,还要修改数据库版本号,如果没有修改数据库版本号,那么再调表对象的时候就会报出一个经典错误,no such table,但凡报这个错误都是你数据版本号没有修改。
    如果要修改表的字段或者增加字段,相对来说稍微麻烦一点。DBFLOW专门提供了AlterTableMigration<T>这个类来修改表相关的资料。以User2Model这个表为例,假如说我们要增加一个字段timeStamp是long类型的,不仅改数据库版本号,同时在类对象中增加 @Column
    private long timeStamp; 字段以外,还需要增加咱们刚才提到的AlterTableMigration的子类来修改

    @Migration(version = AppDataBase.VERSION,database = AppDataBase.class)
    public class Migration1 extends AlterTableMigration<User2Model> {
        public Migration1(Class<User2Model> table) {
            super(table);
        }
    
        @Override
        public void onPreMigrate() {
            super.onPreMigrate();
            addColumn(SQLiteType.INTEGER,User2Model_Table.timeStamp.getNameAlias().name());
        }
    }
    

    继承AlterTableMigration重写onPreMigrate,在里面写你需要
    修改表的操作,这里我们需要增加一个字段addColumn(SQLiteType.INTEGER,User2Model_Table.timeStamp.getNameAlias().name()); 这样就ok了

    总结

    DBFLOW是一个很强大的ORM框架,不仅有文中提到这些基本操作,它还支持Kotlin语言、RxJava以及各种高级用法,不过这些一般在我们客户端使用的情况不多,这里不作为重点介绍,感兴趣的小伙伴可以看一下官网的介绍https://agrosner.gitbooks.io/dbflow/content/StoringData.html

    最后的最后放上我的github地址:https://github.com/kaka10xiaobang/DBFLOW_DEMO

    相关文章

      网友评论

      • 那一年我两岁:请问,如何修改数据表中字段的类型?
        那一年我两岁:@肖邦kaka 请问调用哪个方法()?
        肖邦kaka:继承AlterTableMigration对象,重写onPreMigrate()方法,在里面修改表字段的类型就可以了

      本文标题:Android最好用的数据库框架——DBFLOW全面解析

      本文链接:https://www.haomeiwen.com/subject/yaihjftx.html