ObjectBox 官网:http://objectbox.io/html
之前开发项目的时候 ORM 一直用的是 GreenDao ,此次新开项目的时候访问 GreenDao 的官网的时候却发现了一行新的 Note: for new apps we recommend ObjectBox, a new object-oriented database that is much faster than SQLite and easier to use. For existing apps based on greenDAO we offer DaoCompat for an easy switch (see also the announcement).java
看来 GreenDao 这个浓眉大眼的也准备叛变革命了。。。react
很久没有正儿八经地搞应用开发了,新的轮子已经出现,怎么可以中止不前,研究之,那么这个 ObjectBox 究竟是何方神圣呢?android
瞅一眼官网简介:ObjectBox is a super fast mobile database that persists objects. It lets you avoid many repetitive tasks and offers a simple interface to your data. 翻译一下就是:更快,更简单。翻了一下 FAQ,对比了一下 ObjectBox 和 谷歌两位亲儿子 Realm 和 Room ,以下图:git
从图上能够看出除了在加载 100k 的大量数据的时候 ObjectBox 的速度慢于 Realm,在执行其余数据操做的时候 ObjectBox 的性能对其余两位都是近乎碾压式的存在。github
在引入后对 apk 包的大小影响方面,ObjectBox 和 Realm 分别在 1-1.5MB 和 3-4MB ,Room 由于是对 SQLite 的封装,只有 50KB 左右。而在增长的方法数量方面,Room 的 300 个方法也远少于 Room 的 2000 个方法和 ObjectBox 的 1300 个方法。关于三者的对比,能够看这篇文章:https://notes.devlabs.bg/realm-objectbox-or-room-which-one-is-for-you-3a552234fd6e 。数据库
若是不考虑对包的体积大小的影响,只考虑性能的话,彷佛就有了选择 ObjectBox 的理由。api
Note : 一般我选择 ORM 的首要条件就是支持 RxJava(是时候展现我多年RxJava脑残粉的身份了),然鹅,ObjectBox 的团队彷佛对 RxJava 不太感冒,主要是介意引入RxJava 以后急剧增长的包体积和方法数,因此 ObjectBox 本身封装了一套支持 Reactive Extensions 的接口。浏览器
首先,在 Project 级别的 build.gradle 文件里添加以下脚本:bash
buildscript {
ext.objectboxVersion = '1.5.0'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
}
}
复制代码
而后,在 Module 级别的 build.gradle 文件里添加以下脚本:
dependencies {
// 这一句是添加 RxJava 扩展
compile 'io.objectbox:objectbox-rxjava:0.9.8'
// 下面这两句是 ObjectBox 很骚气的一个功能——DataBrowser, 经过浏览器来调试和浏览数据库的数据
debugImplementation "io.objectbox:objectbox-android-objectbrowser:$objectboxVersion"
releaseImplementation "io.objectbox:objectbox-android:$objectboxVersion"
}
// ObjectBox browser dependencies must be set before applying the plugin so it does not add objectbox-android
// (would result in two conflicting versions, e.g. "Duplicate files copied in APK lib/armeabi-v7a/libobjectbox.so").
apply plugin: 'io.objectbox'
复制代码
注意这里的 apply plugin: 'io.objectbox' 必定要添加到 dependencies 模块后面(已经踩过这个坑了,直接按照官网的 Get Started 的集成方式有点问题)。
在 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);
}
Log.d("App", "Using ObjectBox " + BoxStore.getVersion() + " (" +
BoxStore.getVersionNative() + ")");
}
public BoxStore getBoxStore() {
return boxStore;
}
复制代码
实体类格式(最简单的只要加两个注解就够了,更详细的用法能够参考官方文档):
package io.objectbox.example;
import java.util.Date;
import io.objectbox.annotation.Entity;
import io.objectbox.annotation.Generated;
import io.objectbox.annotation.Id;
import io.objectbox.annotation.apihint.Internal;
@Entity
public class Note {
// 注意这里的 @Id 注解是必须的,和 GreenDao 不一样,GreenDao 能够省略,可是若是你的业务字段已经有了 一个名字为 id 的字段,能够取一个别的名字啊~
@Id
long boxId;
String text;
String comment;
Date date;
public Note(long id, String text, String comment, Date date) {
this.boxId = id;
this.text = text;
this.comment = comment;
this.date = date;
}
public Note() {
}
public long getId() {
return this.boxId;
}
public void setId(long id) {
this.boxId = id;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
public String getComment() {
return this.comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
}
复制代码
在 Activity 执行查询(多余的业务代码已经被我省略):
public class NoteActivity extends Activity {
private Box<Note> notesBox;
private Query<Note> notesQuery;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
BoxStore boxStore = ((App) getApplication()).getBoxStore();
notesBox = boxStore.boxFor(Note.class);
// query all notes, sorted a-z by their text
(http://greenrobot.org/objectbox/documentation/queries/)
notesQuery = notesBox.query().order(Note_.text).build();
updateNotes();
}
/** Manual trigger to re-query and update the UI. For a reactive alternative check {@link ReactiveNoteActivity}. */
private void updateNotes() {
List<Note> notes = notesQuery.find();
}
private void addNote() {
Note note = new Note();
note.setText(noteText);
note.setComment(comment);
note.setDate(new Date());
notesBox.put(note);
Log.d(App.TAG, "Inserted new note, ID: " + note.getId());
}
}
复制代码
一样在 Activity 中执行查询:
/** An alternative to {@link NoteActivity} using a reactive query (without RxJava, just plain ObjectBox API). */
public class ReactiveNoteActivity extends Activity {
private Box<Note> notesBox;
private Query<Note> notesQuery;
private DataSubscriptionList subscriptions = new DataSubscriptionList();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
notesBox = ((App) getApplication()).getBoxStore().boxFor(Note.class);
// query all notes, sorted a-z by their text
// (http://greenrobot.org/objectbox/documentation/queries/)
notesQuery = notesBox.query().order(Note_.text).build();
// Reactive query (http://greenrobot.org/objectbox/documentation/data-observers- reactive-extensions/)
notesQuery.subscribe()
.onError(new ErrorObserver() {
@Override
public void onError(Throwable th) {
}
})
// 官方推荐的作法是对 data observers 持有弱引用,防止忘记 cancel subscriptions,
// 可是最好仍是记得及时 cancel subscriptions(例如在 onPause、onStop 或者
// onDestroy 方法中)
.weak()
.on(AndroidScheduler.mainThread())
.observer(new DataObserver<List<Note>>() {
@Override
public void onData(List<Note> notes) {
// 只要数据库里的数据发生了变化,这里的方法就会被回调执行,至关智能。。。
// 业务代码
}
});
}
@Override
protected void onDestroy() {
subscriptions.cancel();
super.onDestroy();
}
private void addNote() {
Note note = new Note();
note.setText(noteText);
note.setComment(comment);
note.setDate(new Date());
notesBox.put(note);
Log.d(App.TAG, "Inserted new note, ID: " + note.getId());
}
}
复制代码
上面的用法看上去就像傻瓜版的 RxJava,上手容易,概念理解也简单,可是并无 RxJava那么强大的功能,因此若是在应对更复杂的业务逻辑的时候,仍是须要引入 RxJava ,示例以下:
Query query = box.query().build();
RxQuery.observable(query).subscribe(this);
复制代码
RxQuery 可使用 Flowable、Observable、Single 来订阅查询结果,目前 ObjectBox 只支持 RxJava 2 。
添加权限
<uses-permission android:name="android.permission.INTERNET" />
复制代码
在 Application 开启调试
boxStore = MyObjectBox.builder().androidContext(App.this).build();
if (BuildConfig.DEBUG) {
boolean started = new AndroidObjectBrowser(boxStore).start(this);
Log.i("ObjectBrowser", "Started: " + started);
}
复制代码
执行命令
adb forward tcp:8090 tcp:8090
复制代码
在电脑浏览器中访问
http://localhost:8090/index.html
复制代码
效果贼6:
最关键的问题是,若是 put、find 这些方法全是同步的,对于大量数据的存和查都是耗时操做,若是直接写在主线程会阻塞主线程,尤为是 find 方法,而 ObjectBox 的 Reactive 封装显然没有 RxJava 那么强大,GreenDao对RxJava的支持很是好,若是要封装数据库框架的话进行线程切换很是方便,可是我在ObjectBox的官方文档里暂时还没发现对各个方法的执行线程的明确说明。我已经在 Github 提了 issue ,不过还没人回我,有待继续研究。
集成方便简单,调试效果拔群,终于不用再用 DDMS + SQLite Export 调试了(每次手动导数据那叫一个痛苦,后来据说加了一个自动同步的功能,没细研究,不过跟 ObjectBox 的 DataBroswer 是无法比),调试效果很棒,不用写 SQL 。可是感受仍有继续改进的空间,简单化的同时也牺牲了一部分功能的强大和灵活性,相比较而言可能 GreenDao 会更成熟一点,固然官网也提供了从 GreenDao 转到 ObjectBox 的方法。第一次的使用体验仍是很不错的,有机会的话能够研究一下源码,探究一下高性能的缘由。