ObjectBox 集成指南

ObjectBox 簡介

​ 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

ObjectBox 集成

​ 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 的集成方式有點問題)。

ObjectBox 簡單用法

​ 在 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());
    }

}
複製代碼

ObjectBox 的 Reactive 用法

​ 一樣在 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 的方法。第一次的使用體驗仍是很不錯的,有機會的話能夠研究一下源碼,探究一下高性能的緣由。

歡迎關注個人公衆號:cmder

相關文章
相關標籤/搜索