数据监听和RX(Data Observers and Reactive Extensions)
通过以下方式,ObjectBox可以让您的应用轻松应对数据变更:
- 数据监听(data observers)
- Reactive extensions
- Rxjava的适配库
数据监听
第一个例子:
//第一条语句创建一个常规查询来获取未完成的 Task 对象。Queryquery = 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{ void onData(T data);}复制代码
这个观察者在两种情况下被ObjectBox调用:
- 订阅之后
- 数据变更
onData() 被异步线程调用,并且线程解耦(调用线程不是 引起数据变化的线程,比如:不是提交修改事务的线程,请记住)
观察全部变化
BoxStore允许 DataObserver 订阅对象类型。假设您想观察 待办事项列表应用的Task 对象:
DataObservertaskObserver = ...;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(); Queryquery = 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允许将观察者从后台线程切换到主线程。我们来看看上面的待办任务示例的修订版本:
Queryquery = 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{ 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都将在后台线程上运行 。