Agera 使用著名的 觀察者模式 作為響應(yīng)式編程的驅(qū)動(dòng)機(jī)制。
被觀察者(observable)實(shí)現(xiàn)Observable
接口, 并向所有注冊(cè)的觀察者們(observers)廣播事件。
觀察者(observer)實(shí)現(xiàn)Updatable
接口, 可以注冊(cè)和注銷到Observable
中,接受通知事件觸發(fā)更新操作,故此命名為Updatable
。
Observable
public interface Observable {
void addUpdatable(@NonNull Updatable updatable);
void removeUpdatable(@NonNull Updatable updatable);
}
observer
public interface Updatable {
void update();
}
接下來的文檔中,將用_observable_和_updatable_來表示被觀察者和觀察者對(duì)象。
Agera 使用 push event, pull data 模型(推送事件,拉取數(shù)據(jù))。 push event:被觀察者只做事件通知,不攜帶任何數(shù)據(jù); pull data:觀察者根據(jù)自己需要從數(shù)據(jù)倉庫(Repository.get())拉取數(shù)據(jù)。
這種 push event, pull data 模型, 觀察者就不需要提供數(shù)據(jù)了(ps:通常意義上的觀察者模式是支持?jǐn)y帶數(shù)據(jù)和不攜帶數(shù)據(jù)的), 可以封裝簡單的事件, 比如 按鈕點(diǎn)擊事件,下拉刷新觸發(fā)事件,一個(gè)同步信號(hào)(比如:谷歌推送(GCM)消息到app)等。
// push event
mObservable = new OnClickObservable() {
@Override
public void onClick(View view) {
dispatchUpdate();
}
};
@Override
public void update() {
// pull data
String result = mRepository.get();
mBinding.setImageUrl(result);
}
然而, 被觀察者一般也提供數(shù)據(jù)。一個(gè)可以提供數(shù)據(jù),還可以定義在提供數(shù)據(jù)發(fā)生變化時(shí)的事件的被觀察者,稱為數(shù)據(jù)倉庫(Repository
)。
這并沒有改變 push event, pull data 模型: 當(dāng)數(shù)據(jù)變化時(shí),數(shù)據(jù)倉庫(Repository
)通知所有觀察者更新;觀察者各自從數(shù)據(jù)倉庫(Repository
)拉取數(shù)據(jù)響應(yīng)事件。
這種模型的好處是:將數(shù)據(jù)和事件通知分離,數(shù)據(jù)倉庫(Repository
)可以實(shí)現(xiàn)懶加載。
由于 push event, pull data 模型和多線程情況下,觀察者可能看不到數(shù)據(jù)全部的更新記錄。 這是特意設(shè)計(jì)的: 因?yàn)榇蠖鄶?shù)情況下(尤其更新app UI), 本來就只需要關(guān)心最新的數(shù)據(jù)。
一個(gè)典型Agera風(fēng)格的響應(yīng)式Client由以下幾部分組成:
ps: 一個(gè)Repository的定義
// 數(shù)據(jù)提供者 text color Supplier
Supplier<Integer> supplier = new Supplier<Integer>() {
@NonNull
@Override
public Integer get() {
return MockRandomData.getRandomColor();
}
};
mRepository = Repositories.repositoryWithInitialValue(0)
.observe(mObservable)// 事件源
.onUpdatesPerLoop()
.thenGetFrom(supplier)// 數(shù)據(jù)源
.compile();