鍍金池/ 教程/ Android/ Reactive programming
Custom observables
Compiled functions
Reactive programming
Reservoirs and parallelism
Incrementally Agerifying legacy code
Observables and updatables
Compiled repositories
Repositories

Reactive programming

Agera 使用著名的 觀察者模式 作為響應(yīng)式編程的驅(qū)動機制。 被觀察者(observable)實現(xiàn)Observable接口, 并向所有注冊的觀察者們(observers)廣播事件。 觀察者(observer)實現(xiàn)Updatable接口, 可以注冊和注銷到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_來表示被觀察者和觀察者對象。

Push event, pull data

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:通常意義上的觀察者模式是支持攜帶數(shù)據(jù)和不攜帶數(shù)據(jù)的), 可以封裝簡單的事件, 比如 按鈕點擊事件,下拉刷新觸發(fā)事件,一個同步信號(比如:谷歌推送(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ù)。一個可以提供數(shù)據(jù),還可以定義在提供數(shù)據(jù)發(fā)生變化時的事件的被觀察者,稱為數(shù)據(jù)倉庫(Repository)。 這并沒有改變 push event, pull data 模型: 當數(shù)據(jù)變化時,數(shù)據(jù)倉庫(Repository)通知所有觀察者更新;觀察者各自從數(shù)據(jù)倉庫(Repository)拉取數(shù)據(jù)響應(yīng)事件。 這種模型的好處是:將數(shù)據(jù)和事件通知分離,數(shù)據(jù)倉庫(Repository)可以實現(xiàn)懶加載。

由于 push event, pull data 模型和多線程情況下,觀察者可能看不到數(shù)據(jù)全部的更新記錄。 這是特意設(shè)計的: 因為大多數(shù)情況下(尤其更新app UI), 本來就只需要關(guān)心最新的數(shù)據(jù)。

一個典型Agera風(fēng)格的響應(yīng)式Client由以下幾部分組成:

  • 向Observables注冊一個Updatable,用于事件通知;
  • 可直接調(diào)用update,來初始化或更改Client狀態(tài);
  • 等待Observables的通知,拉取最新的數(shù)據(jù)來更新Client;
  • 當不需要事件了,需要向Observables注銷updatable,釋放資源。

ps: 一個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();