正如前文 Agera官方Wiki翻译(二)——响应式编程 所述,被观察者(observable)表示事件源,updatable 观察这些事件。updatable 使用 Observable.addUpdatable(Updatable)
注册对被观察者(observable)的观察,使用 Observable.removeUpdatable(Updatable)
解除注册。事件以 Updatable.update()
的形式被分发到 updatable。
Activity 可以通过如下方式观察来自被观察者(observable)的事件:
// Activity 实现 Updatable,说明它要响应事件 public class MyUpdatableActivity extends Activity implements Updatable { // 事件源 private Observable observable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); observable = new MyObservable(); } @Override public void update() { // Act on the event // 有事件发生时就会调用 update } @Override protected void onResume() { super.onResume(); // 生命周期调整 observable.addUpdatable(this); update(); } @Override protected void onPause() { super.onPause(); // 生命周期调整 observable.removeUpdatable(this); } }
Updatable 的注册与取消注册必须成对使用。多次注册同一个 updatable 是非法操作,对未注册的 updatable 取消注册也是非法操作,多次取消 updatable 也属于非法操作,诸如此类。
被观察者(observable)通过被观察(至少被一个 updatable 注册)这一行为变为 活动 状态,通过被取消观察(没有被任何 updatables 注册)变为 不活动 状态。也就是说,updatable 如果要激活一个不活动的 observable 就注册上去;如果 updatable 是 observable 的唯一观察者,那 updatable 取消注册 observable 就变为未激活。
被观察者(observable)可以观察其他“上游”的 observables,所谓“上游”是指这样形成了事件的传递路径,并将上游事件转换为自己的事件。一个典型的例子就是一个源(repository)的数据依赖于别的源的数据。为确保线路的正确性,这样一个处于中间位置的被观察者通常保留上游 observables 的强引用,但通常只在自己处于激活状态时将自己内部的 updatable 注册到上游,在自己处于不激活状态时取消对上游的注册。这就意味着,大多数下游 updatables(不受中间 observables 管理的)最终以事件链的形式控制所有 observables 的激活与不激活。
事件链这个特性在构建感知 UI 生命周期的响应式结构时最为有用。UI 元素如 Activity、Fragment 或者其中的一个 View,其活动生命周期由 Android 下成堆的生命周期事件定义,例如从 onStart
到 onStop
,从 onResume
到 onPause
,从 onAttachedToWindow
到 onDetachedFromWindow
等等。加入一个 UI 元素成为或者拥有一个 updatable,这个 updatable 的作用是获取源提供的数据并更新 UI。这个源反过来使用了其他的事件源和数据源来构建它自己的数据。
在 UI 元素的生命周期之初,上述的 updatable 被注册上去,这样源就处于激活状态。这将链接事件链并激活所有相关数据的处理流程,保证 UI 上的数据是最新的。
在 UI 元素生命周期的最后,updatable 从同一个源上取消注册,假设再没有 updatables 再保持 observable 活动,这样事件链就会按照链接顺序分解。如果 UI 元素不再活动(例如由于 Activity 销毁了),因为当系统不活动时没有下游的引用了,UI 元素被垃圾回收释放,这样就容易防止内存泄露。
Agera 提倡明确的线程,并使用 Loopers(大量存在,例如 APP 的主 Loopers 和 IntentService 工作线程的 Looper)来定义以下的线程契约。
对于内部的生命周期激活处理,每个 observable 都在生命时与一个工作 Looper 建立联系,即 observable 实例化处的线程的 Looper。如果 observable 在活动时观察其他 observable,它内部的 updatable 将会从当前工作 Looper 线程注册到上游 observables。
updatable 必须在 Looper 线程上对 observable 进行注册,但不必与 observable 运行的工作 Looper 相同。observable 将使用同一个 Looper 线程向 updatable 分发 Updatable.update()
调用。
updatable 可以在任何线程被取消注册,但是为了避免 updatable 取消注册之后在 Looper 内部处理被事件被分发过来这一竞争条件,建议 updatable 在注册时的同一个 Looper 线程取消注册。
Looper 的活动时间需要与依赖他的 observables 或注册的 updatables 一样长,由开发者负责维护这一点。由于 Loopers 死了造成的泄漏和异常,都应有开发者负责。在实际中,可是,很少会使用出了主 Looper 之外的其他 Looper,而主 Looper 总是活动的。