ObjectBox[六]数据监听和RX(Data Observers and Reactive Extensions)

来源:互联网 发布:mac cad菜单栏不见了 编辑:程序博客网 时间:2024/05/21 15:05

ObjectBox[一] 特性

ObjectBox[二] 教程:如何开始使用ObjectBox

ObjectBox[三] 教程:安装和基础

ObjectBox[四] 数据库持久化之实体注解

ObjectBox[五] 基本操作:查询

ObjectBox[六] 数据监听和RX(Data Observers and Reactive Extensions)

ObjectBox[七] 支持LiveData(Android体系结构组件)

ObjectBox[八] 关系

ObjectBox[九] 数据模型变更

ObjectBox[十] 自定义类型

ObjectBox[十一] 事务

ObjectBox[十二] Meta Model, IDs, and UIDs

ObjectBox[十三] 数据调试


(私货:如果使用过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()中取消 订阅 。

观察者和事务

观察者通知发生在事务提交后。对于某些场景,了解事务边界尤为重要。如果调用putremove,隐式事务被启动并提交。例如,这段代码会触发两次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信息变换为总数,所以DataObserveronData()中将接受 Long作为参数 。

虽然lambda语法非常简洁,但我们还是来看一下io.objectbox.reactive.Transformer接口:

public interface DataTransformer<FROM, TO> {    TO transform(FROM source) throws Exception;}

一些关于变换的附加说明:

  • 实际上类型可以不变。从技术上讲,可以在Transformer中处理一些数据然后发出去,(私货:例如过滤等等)

  • Transformer是异步执行。可以执行一些耗时操作。

异常

也许你注意到变换实现可能会抛出任何类型的异常。此外, DataObserver 可能会引发 RuntimeException。在这两种情况下,您都可以实现 ErrorObserverio.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()方法指定线程,否则 DataObserverErrorObserver都将在后台线程上运行 。

ObjectBox RxJava扩展库

通过设计,ObjectBox的核心中不包含Rxjava的任何库。正如您在ObjectBox之前所看到的那样,您可以使用简单的方法来转换数据,异步处理,线程调度和一次性(单个)通知。不过,你仍然可能想要与强大的RxJava 2(我们没有计划支持RxJava 1)整合。为此,我们创建了ObjectBox RxJava扩展库。它需要额外的Gradle依赖(确保检查最新版本):

compile 'io.objectbox:objectbox-rxjava:0.9.8'

有了这个,你可以使用类 RxQueryRxBoxStore。两个静态方法封装QueryBoxStore
监听所有变化,你可以使用 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/

阅读全文
0 0
原创粉丝点击