ObjectBox[二] 教程:如何开始使用ObjectBox
ObjectBox[六] 数据监听和RX(Data Observers and Reactive Extensions)
ObjectBox[七] 支持LiveData(Android体系结构组件)
ObjectBox[十二] Meta Model, IDs, and UIDs
(私货:如果使用过Rxjava的话,这三种方式非常类似)
通过以下方式,ObjectBox可以让您的应用轻松应对数据变更:
- 数据监听(data observers)
- Reactive extensions
- Rxjava的适配库
这三种方法让我们方便处理数据流。
数据监听
第一个例子:
Query<Task> query = taskBox.query().equal(Task_.complete, false).build();
query.subscribe(subscriptions).on(AndroidScheduler.mainThread()).observer(data -> updateUi(data));
第一条语句创建一个常规查询来获取未完成的 Task
对象。第二条将观察者连接到查询。这是发生了什么事情:
- 查询在后台执行
- 一旦查询完成,观察者获得结果数据
- 以后未完成对象如果有更改时 ,查询将再次执行
- 一旦查询结果有变化,它们被传递给观察者
- 观察者在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<Task> query = taskBox.query().equal(Task_.completed, false).build();
subscription = query.subscribe().observer(data -> updateUi(data));
那么我们的观察者什么时候被调用?观察者订阅时,查询将在一个单独的线程中运行。一旦查询结束,它将被传递给观察者。这是对观察者的第一次调用。
现在让我们改变一个Task 并存储在ObjectBox中。哪里和怎样都没关系; 可能是将任务标记为已完成的用户,或者在与服务器同步期间某些后端线程将其他任务添加进去。在任何情况下,查询都会通知所有观察者具有更新的查询结果。
请注意,这种模式可以大大简化您的代码:您的数据有一个地方用来更新您的用户界面。没有单独的初始化代码,没有重发的事件,没有重建的查询等。
取消订阅
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几乎就像学习一种新的语言)和大小。所以,让我们现在保持简单和整洁。
线程切换
在Android上,UI更新只能在主线程上进行。幸运的是,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
作为参数 。
虽然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(...)
单一通知与仅变更
在订阅查询时, DataObserver
默认情况下会在两种情况下触发:
- 初始查询结果(订阅后)
- 更新后的查询结果(数据库数据已更改)
有时你可能只需要其中一项。这就是 single()
和 onlyChanges()
方法的用途(在subscribe()
之后调用它们 )。single()
比较特殊,一旦观察者得到通知后就会自动取消订阅。您仍然可以手动取消它们,以确保在某个点上不会对观察者发起呼叫。
弱引用
为了避免内存泄漏和异常,subscriptions 需要手动取消订阅。当然也可以使用弱引用,在subscribe()
后调用weak()
。
线程概述
如前所说,线程总结如下:
- 查询执行在后台线程上运行(仅限于此任务)
DataTransformer
在后台线程上运行(仅限于此任务)- 除非通过
on()
方法指定线程,否则DataObserver
和ErrorObserver
都将在后台线程上运行 。
ObjectBox RxJava扩展库
通过设计,ObjectBox的核心中不包含Rxjava的任何库。正如您在ObjectBox之前所看到的那样,您可以使用简单的方法来转换数据,异步处理,线程调度和一次性(单个)通知。不过,你仍然可能想要与强大的RxJava 2(我们没有计划支持RxJava 1)整合。为此,我们创建了ObjectBox RxJava扩展库。它需要额外的Gradle依赖(确保检查最新版本):
compile 'io.objectbox:objectbox-rxjava:0.9.8'
有了这个,你可以使用类 RxQuery
和 RxBoxStore
。两个静态方法封装Query
和BoxStore
。
监听所有变化,你可以使用 RxBoxStore
来创建Observable
。
RxQuery
也提供了如下三种Rx:
- Flowable
- Observable
- Single
用法如下:
Query query = box.query().build();
RxQuery.observable(query).subscribe(this);
扩展库在GitHub上作为单独的开源项目进行管理。
原文:http://objectbox.io/documentation/data-observers-reactive-extensions/