ObjectBox 笔记

作者: chauI | 来源:发表于2017-07-20 18:37 被阅读2360次

    EventBus 和 GreenDao 的老东家 GreenRobot 推出的移动端数据库架构。

    优点:

    • 速度快,号称比目前主流数据库架构快 5-15 倍
    • NoSql,没有 rows、columns、SQL,是完全面向对象的 API
    • 数据库升级做到完全自动

    目前正式版本号为 V1.5.5 - 2018/04/17,以及 Beta 版的 V2.0.0。

    以下笔记整理于官方文档,更多可见于官方的 Demo

    简单使用

    • 依赖

    根目录下 build.gradle

    buildscript {
        ext.objectboxVersion = '1.5.0'
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.0.1'
            classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
        }
    }
    

    app 下 build.gradle

    apply plugin: 'com.android.application'
    apply plugin: 'io.objectbox'
    

    如果项目中用引入 Kotlin support,需要在上面额外添加:

    apply plugin: 'kotlin-android' // if using Kotlin
    apply plugin: 'kotlin-kapt' // if using Kotlin
    

    至此 ObjectBox 插件将会自动添加其余的依赖,但假如插件无法添加所需的库和注释处理器到依赖就需要手动添加:

    //java only
    dependencies {
        // all below should be added automatically by the plugin
        compile "io.objectbox:objectbox-android:$objectboxVersion"
        annotationProcessor "io.objectbox:objectbox-processor:$objectboxVersion"
    }
    
    ****************************************************************************
    
    //kotiln super
    dependencies {
        // all below should be added automatically by the plugin
        compile "io.objectbox:objectbox-android:$objectboxVersion"
        kapt "io.objectbox:objectbox-processor:$objectboxVersion"
        // some useful Kotlin extension functions
        compile "io.objectbox:objectbox-kotlin:$objectboxVersion" 
    }
    
    • 初始化

    官方推荐在 Application 中初始化 ObjectBox 的实例:

    private static BoxStore mBoxStore;
    @Override
    public void onCreate() {
        super.onCreate();
        mBoxStore = MyObjectBox.builder().androidContext(this).build();
    }
    public BoxStore getBoxStore(){
        return mBoxStore;
    }
    

    不要忘了在 AndroidManifest 引用自定义的 Application,然后在代码中获取:

    notesBox = ((App) getApplication()).getBoxStore().boxFor(TestObjectBoxBean.class);
    

    有一点要提一下, 如果是第一次引入 ObjectBox,这里的 MyObjectBox 是找不到的,创建了对应的实体类后 Build > Make project 或者 Rebuild Project() 才会出现。

    • 数据模型

    和现在流行的架构一样,ObjectBox 的数据模型使用注解的方式定义:

    @Entity
    public class TestObjectBoxBean {
    
        @Id(assignable = true)
        long id;
    
        @Index
        String name;
    
        @Transient
        String uom;
    
        @NameInDb("age")
        String test;
    }
    
    注解 说明
    @Entity 这个对象需要持久化。
    @Id 这个对象的主键。
    @Index 这个对象中的索引。对经常大量进行查询的字段创建索引,会提高你的查询性能。
    @NameInDb 有的时候数据库中的字段跟你的对象字段不匹配的时候,可以使用此注解。
    @Transient 如果你有某个字段不想被持久化,可以使用此注解。
    @Relation 做一对多,多对一的注解。

    需要注意的是,默认情况下 id 是被 ObjectBox 管理的一个自增 id,也就是说被 @Id 标注的字段不需要也不能手动设置,如果要手动管理应该用 @Id(assignable = true) 标注字段。
    而且被标注为主键的字段应该为 long 型。

    • 增删查改
    TestObjectBoxBean bean = new TestObjectBoxBean();
    ...
    
    //第一步获取 Box 实例
    Box<TestObjectBoxBean> beanBox = ((BApplication) getApplication())
            .getBoxStore().boxFor(TestObjectBoxBean.class);
    
    //新增和修改,put 的参数可以是 list
    beanBox.put(bean);
    
    //删除 id 为 2 的数据
    beanBox.remove(2);
    
    //查询,名字为 T 开头或者 uom 为 kg 的数据
    List<TestObjectBoxBean> item = beanBox.query()
            .startsWith(TestObjectBoxBean_.name,"T")
            .or().equal(TestObjectBoxBean_.uom,"kg")
            .orderDesc(TestObjectBoxBean_.gid).build().find();
    

    查询时,用到了生成类 TestObjectBoxBean_ 通常是实体类加一个下划线。
    使用 builder.equal() 进行设置匹配,调用 startWith() 设置查询条件,find() 可以用于分页。

    实用的 API 还有一些:

    //query.setParameter() 可以修改初始化时 equal() 设置的参数,所以我们可以复用同一个 Query 对象去查询
    Query<User> query = userBox.query().equal(User_.firstName, "").build();
    List<User> joes = query.setParameter(User_.firstName, "Joe").find();
    List<User> jakes = query.setParameter(User_.firstName, "Jake").find();
    
    Query<User> query = builder.build();
    User joe = query.findFirst();//返回第一个结果或 null
    User joe = query.findUnique();//返回唯一的结果,如果查询出多个结果将抛出异常
    
    //偏移量和数据量的限制
    List<User> joes = query.find(/* offset by */ 10, /* limit to */ 5 /* results */);
    
    • Query 的一些方法:
    //property() 可以直接取出属性值而不需要获取实例
    String[] emails = userBox.query().build().property(User_.email).findStrings();
    
    //nullValue() 可以在返回值为 null 时赋一个默认值
    String[] emails = userBox.query().build()
        .property(User_.email).nullValue("unknown").findStrings();
    
    //distinct() 可以去重
    String[] names = userBox.query().build()
        .property(User_.firstName).distinct().findStrings();
    //distinct(StringOrder.CASE_SENSITIVE) 可以设置为大小写敏感,默认是不区分
    
    //可以配合上述的 unique(),在返回值不唯一时抛出异常
    //throws if not exactly one name
    String[] names = userBox.query().build().equal(User_.isAdmin, true)  
        .property(User_.firstName).unique().findStrings();
    
    //也可以添加一些筛选的条件
    //下面的 demo 同样是来着官方文档,这里应该是 Kotlin 的 lambda 格式
    songBox.query().equal(Song_.bandId, bandId)
      // Filter is performed on candidate objects
      .filter((song) -> {
         //return isKeep
         return song.starCount * 2 > song.downloads;
      })
    
    • 事务

    Box 实例下的 put 和 remove 的执行实际上已经是事务的。
    除此之外显性的使用事务也是可以的,ObjectBox 提供了几个 api:

    API 说明
    runInTx 在给定的 runnable 中运行的事务。
    runInReadTx 只读事务,不同于 runInTx,允许并发读取
    runInTxAsync 运行在一个单独的线程中执行,执行完成后,返回 callback。
    callInTx 与runInTx 相似,不同的是可以有返回值。
    boxStore.runInTx(new Runnable() {
      @Override
      public void run() {
         for(User user: allUsers) {
             if(modify(user)) box.put(user);
             else box.remove(user);
           }
        }
    });
    
    • 数据库升级

    首先,在要修改的字段添加 @Uid 注解。


    然后 Build -> Make Project,

    此时就可以直接修改字段的名称。

    • Rx 监听
    Query<TestObjectBoxBean> builder = beanBox.query().build();
    builder.subscribe().on(AndroidScheduler.mainThread()).observer(new DataObserver<List<TestObjectBoxBean>>() {
        @Override
        public void onData(List<TestObjectBoxBean> testObjectBoxBeen) {
          //the query is executed in the background
          //once the query finishes the observer gets the result data
          //once updated query results are in, they are propagated to the observer
        }
    });
    
    //Kotlin 
    Query<Task> query = beanBox.query().equal(Task_.complete, false).build();
    query.subscribe(subscriptions)
         .on(AndroidScheduler.mainThread())
         .observer(data -> updateUi(data));
    

    需要注意的是,对查询出来的数据进行修改会触发查询,查询结果同样会回调到这里的观察者。

    • 另外

    官方有这样一个提示,假如需要插入或修改多条数据,可以这样做:

    for(User user: allUsers) {
       modify(user); // modifies properties of given user
       box.put(user);
    }
    

    但这种做法可能会需要较多的时间、花费更多的性能,正确做法:

    for(User user: allUsers) {
       modify(user); // modifies properties of given user
    }
    box.put(allUsers);
    

    相关文章

      网友评论

        本文标题:ObjectBox 笔记

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