Android数据库解决方案:Object Box

1,148 阅读3分钟
原文链接: zhuanlan.zhihu.com

一、我的需求

我希望在我的Android项目中构建一套缓存系统。当我将从服务器上请求到的JSON反序列化为JAVA对象时,我将该对象存入缓存,保存起来。下次假如网络请求失败,我从缓存中读取上一次保存好的对象展现给用户。

写完回来,发现Object Box并解决不了对象持久化存储的问题,因为其不支持内部类。所以这个问题还是得用Serializable来完成。不过,经此一错,我对数据库的理解更加深刻了。

那就是数据库,不管是SQL还是NoSQL,都是用表来存数据的。它存储的对象是一组数据,而不是单一数据。

二、目前的技术解决方案

  1. Serializable:序列化对象为文件,并保存在文件里
  2. SharedPreferences:Android官方提供的缓存文件,以XML形式存储
  3. SQLite:官方数据库
  4. greenDAO:基于SQLite的轻量级ORM
  5. Realm:第三方数据库
  6. Object Box:第三方数据库

首先,我的数据需要有保密性,不能用户直接从手机中能拷出来,故Serializable与SharedPreferences不予考虑。

其次,SQLite要写SQL语句,而我更希望使用NoSQL的特性,故不予考虑。

所以,最后把目光放在了Realm与greenDAO解决方案上。

在知乎上搜,看Realm的BUG有不少,我希望用一个风评比较好的数据库,故Realm也不予考虑。

所以,最后目光看向了greenDAO这个基于SQLite的抽象层上面。

进入官方网站一看,发现该公司推出了一个新的产品叫做Object Box。不知怎的,我也没调研这个坑多不多,但是凭借着黑客的直觉,决定使用该方案作为我的技术解决方案。

三、安装Object Box

gradle:将黑体部分添加至你的项目中

// In your root build.gradle file:
buildscript {
    ext.objectboxVersion = '1.2.1'
    repositories {
        jcenter()
        maven { url "http://objectbox.net/beta-repo/" }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
    }
}
 
allprojects {
    repositories {
        jcenter()
        maven { url "http://objectbox.net/beta-repo/" }
    }
}
 
// In your (app) module build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'io.objectbox'

四、创建实体类Bean并编译你的项目

创建一个Bean.java文件,然后在Android Studio中按Ctrl + F9

里面被@Id标注的是一个由ObjectBox维护的自增ID,我们不用手动给其赋值。

@Entity
public class Bean {
    @Id
    private
    long id;

    public Bean(String uuid, String token) {
        this.uuid = uuid;
        this.token = token;
    }

    private String uuid;

    private String token;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

五、创建App.java并在AndroidManifest.xml中配置

public class App extends Application {

    public static final String TAG = "ObjectBoxExample";
    public static final boolean EXTERNAL_DIR = false;

    private BoxStore boxStore;

    @Override
    public void onCreate() {
        super.onCreate();
        boxStore = MyObjectBox.builder().androidContext(App.this).build();
        if (BuildConfig.DEBUG) {
            new AndroidObjectBrowser(boxStore).start(this);
        }
    }

    public BoxStore getBoxStore() {
        return boxStore;
    }
}

六、获取BeanBox

public class MainActivity extends AppCompatActivity {

    private Box<Bean> beanBox;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BoxStore boxStore = ((App) getApplication()).getBoxStore();
        beanBox = boxStore.boxFor(Bean.class);
    }
}

七、数据库操作:增

    //增
    private void add(Box<Bean> beanBox) {
        Bean bean = new Bean("1234", "fuck");
        if (beanBox != null) {
            beanBox.put(bean);
        }
    }

八、数据库操作:查

查操作,ObjectBox提供了很多API,这里只介绍:equal()

本函数操作:找到一组uuid为1234的bean,返回其中的第一个——beanList.get(0)

    //查
    private Bean query(Box<Bean> beanBox) {
        if (beanBox != null) {
            List<Bean> beanList = beanBox.query().equal(Bean_.uuid, "1234").build().find();
            return beanList.get(0);
        }
        return null;
    }

九、数据库操作:删

删操作,ObjectBox提供了很多API,如上图所示。

用id作为标识删除数据:

    private void delete(Box<Bean> beanBox) {
        if (beanBox != null) {
            beanBox.remove(1);
        }
    }

通过「查操作」获取「想删除的对象」,再通过「删操作」删除该对象。

    //删
    private void delete(Box<Bean> beanBox) {
        Bean bean = query(beanBox);
        if (beanBox != null) {
            beanBox.remove(bean);
        }
    }

十、数据库操作:改

这里也是,先通过「查操作」获取「想改的对象」,然后修改该对象的值,最后调用put()就算是完成了「改」

    //改
    private void update(Box<Bean> beanBox) {
        Bean bean = query(beanBox);
        bean.setToken("FUCK YOU");
        if (beanBox != null) {
            beanBox.put(bean);
        }
    }

十一、注意:「删」、「改」的函数里,我都调用了「查」——query()

别起急