2018.03.31、Android-ObjectBox-監聽

Traning發表於2018-04-02

資料監聽和RX(Data Observers and Reactive Extensions)

通過以下方式,ObjectBox可以讓您的應用輕鬆應對資料變更:

  • 資料監聽(data observers)
  • Reactive extensions
  • Rxjava的適配庫

資料監聽

第一個例子:

//第一條語句建立一個常規查詢來獲取未完成的 Task 物件。
Query<Task> query = taskBox.query()
                            .equal(Task_.complete,false)
                            .build();
                           
// 第二條將觀察者連線到查詢。                           
query.subscribe(subscriptions)
     .on(AndroidScheduler.mainThread())
     .observer(data -> updateUi(data));
     
複製程式碼
  • 查詢在後臺執行
  • 一旦查詢完成,觀察者獲得結果資料
  • 以後未完成物件如果有更改時 ,查詢將再次執行
  • 一旦查詢結果有變化,它們被傳遞給觀察者
  • 觀察者在Android的主執行緒上被呼叫

subscribe(subscriptions):這是一個所有訂閱的集合,如果你想要停止觀察,可以呼叫cancel()來取消。

Data Observers Basics

當物件改變時,ObjectBox通知訂閱的資料觀察者。觀察者可以訂閱某些物件型別的更改(通過BoxStore)或查詢結果。

首先,要建立資料觀察者,您需要實現io.objectbox.reactive.DataObserver介面:

public interface DataObserver<T> {
    void onData(T data);
}
複製程式碼

這個觀察者在兩種情況下被ObjectBox呼叫:

  • 訂閱之後
  • 資料變更

onData() 被非同步執行緒呼叫,並且執行緒解耦(呼叫執行緒不是 引起資料變化的執行緒,比如:不是提交修改事務的執行緒,請記住)

觀察全部變化

BoxStore允許 DataObserver 訂閱物件型別。假設您想觀察 待辦事項列表應用的Task 物件:

DataObserver<Class> taskObserver = ...;
boxStore.subscribe(Task.class).observer(taskObserver);
複製程式碼

資料庫中Task Box有任何改變則會呼叫taskObserver 。 注意:還有 不帶任何引數的subscribe()。它訂閱觀察者以接收所有可用物件類的更改。

觀察查詢

ObjectBox讓你建立查詢 來找到符合特定條件的物件。
查詢是ObjectBox的重要組成部分:只要您需要特定的一組資料,您就需要使用查詢。

將查詢和觀察者結合在一起會產生一個方便而強大的工具:當相關資料發生變化時,查詢觀察者將自動提供新的結果。假設您在應用中顯示待辦任務列表。您可以使用 DataObserver 獲取尚未完成的所有任務,並將其傳遞給方法 updateUi ()(請注意,我們在此使用lambda語法):

Query query = taskBox.query().equal(Task_.completed, false).build(); subscription = query.subscribe().observer(data -> updateUi(data));

那麼我們的觀察者什麼時候被呼叫?觀察者訂閱時,查詢將在一個單獨的執行緒中執行。一旦查詢結束,它將被傳遞給觀察者。這是對觀察者的第一次呼叫。

請注意,這種模式可以大大簡化您的程式碼:您的資料有一個地方用來更新您的使用者介面。沒有單獨的初始化程式碼,沒有重發的事件,沒有重建的查詢等。

取消訂閱

observer()方法會返回 io.objectbox.reactive.DataSubscription介面的實現:

public interface DataSubscription {
    void cancel();
    boolean isCanceled();
}
複製程式碼

所以,如果你打算取消觀察,可以儲存DataSubscription,呼叫 cancel() 讓ObjectBox去掉該觀察者:

DataSubscription subscription = boxStore.subscribe().observer(myObserver);

// At some later point:
subscription.cancel();
複製程式碼

由於您可能有多個查詢訂閱,我們推薦使用 DataSubscriptionList 來儲存多個 DataSubscription 物件。基本模式是這樣的:

private DataSubscriptionList subscriptions = new DataSubscriptionList();

protected void onStart() {
  super.onStart();
  Query<X> query = box.query()... .build();
  query.subscribe(subscriptions)... .observe(...);
}

protected void onStop() {
  super.onStop();
  subscriptions.cancel();
}
複製程式碼

注意:在Android上,您通常會在onCreate()/ onStart()/ onResume()生命週期方法之一中建立訂閱,並在其對應的onDestroy()/ onStop()/ onPause()中取消 訂閱 。

觀察者和事務

觀察者通知發生在事務提交後。對於某些場景,瞭解事務邊界尤為重要。如果呼叫put 或 remove,隱式事務被啟動並提交。
例如,這段程式碼會觸發兩次User上的資料觀察者:

box.put(friendUser);
box.put(myUser);
複製程式碼

有幾種方法可以將多個操作組合到一個事務中,例如使用 BoxStore類中的 runInTx() 或 callInTx()方法之一。對於我們的簡單例子,我們可以簡單地使用put()接受多個物件的過載方法:

box.put(friendUser, myUser);
複製程式碼

這隻會產生一個事務,從而發出一個 DataObserver 通知。

Reactive Extensions(RX)

ObjectBox為大多數功能提供了簡單和方便的RX。雖然其中大部分是受RxJava的啟發,但實際上並不是基於RxJava。ObjectBox帶來了自己的特性,因為並不是所有的開發人員都熟悉RxJava(對於RxJava ObjectBox庫見下文)。我們不想強加RxJava(〜10k方法)的複雜性(Rx幾乎就像學習一種新的語言)和大小。所以,讓我們現在保持簡單和整潔。

執行緒切換

ObjectBox允許將觀察者從後臺執行緒切換到主執行緒。我們來看看上面的待辦任務示例的修訂版本:

Query<Task> query = taskBox.query().equal(Task_.complete, false).build();
query.subscribe().on(AndroidScheduler.mainThread())
                .observer(data -> updateUi(data));
複製程式碼

on()方法是告訴ObjectBox我們的觀察者被呼叫的執行緒。 AndroidScheduler.mainThread () 是一個內建的排程器實現。您可以 使用自定義 Looper建立 AndroidScheduler,或者實現io.objectbox.reactive.Scheduler介面來自定義一個執行緒切換。

資料變換

也許你想在將資料交給觀察者之前進行資料轉換。比方說,你想跟蹤每種型別的所有儲存物件的總數。BoxStore subscription 返回Class資訊,這個例子展示瞭如何將它們轉化為實際的總數:

boxStore.subscribe()
    .transform(clazz -> return boxStore.boxFor(clazz).count())
    .observer(count -> updateCount(count));
複製程式碼

這段transform程式碼將class資訊變換為總數,所以DataObserver 在onData()中將接受 Long作為引數 。

這段transform程式碼將class資訊變換為總數,所以DataObserver 在onData()中將接受 Long作為引數 。

雖然lambda語法非常簡潔,但我們還是來看一下io.objectbox.reactive.Transformer介面:

public interface DataTransformer<FROM, TO> {
    TO transform(FROM source) throws Exception;
}
複製程式碼
  • 實際上型別可以不變。從技術上講,可以在Transformer中處理一些資料然後發出去,(私貨:例如過濾等等)
  • Transformer是非同步執行。可以執行一些耗時操作。

異常

也許你注意到變換實現可能會丟擲任何型別的異常。此外, DataObserver 可能會引發 RuntimeException。在這兩種情況下,您都可以實現 ErrorObserver :io.objectbox.reactive.ErrorObserver 以收到異常:

public interface ErrorObserver {
    void onError(Throwable th);
}
複製程式碼

在subscribe()之後呼叫它們,實現方式如下:

query.subscribe().onError(new ErrorObserver() {
                    @Override
                    public void onError(Throwable th) {

                    }
                }).observer(...)
複製程式碼

執行緒概述

如前所說,執行緒總結如下:

  • 查詢執行在後臺執行緒上執行(僅限於此任務)
  • DataTransformer 在後臺執行緒上執行(僅限於此任務)
  • 除非通過 on()方法指定執行緒,否則 DataObserver 和 ErrorObserver都將在後臺執行緒上執行 。

相關文章