Locked History Actions

GWT/GWTP/PlaceManager

PlaceManager

※以下は多分に想像も含まれるので注意。

モチベーション

生のGWTを使用したアプリでは、(サードパーティ製のライブラリを使わない限り)ただ一つのhtml上にすべてを描画することになる。 しかし、当然ながら「ページ」を切り替えながらユーザとの対話を行いたいアプリの作成は面倒になる。

例えばDeckLayoutPanelに複数のページウィジェットを重ねておき、見せたいものを指示するという方法がある(つまり紙芝居方式)。 ところが、この方式ではおそらく、

  • すべてのページウィジェットを最初に生成しなくてはならない。
  • ブラウザのバックボタン等に追従しない。

という問題がある。GWTPのPlaceManagerはこれを行うものであり、その機能としては

  • Proxyを使うことにより、ページの生成はオンデマンドで行われる(おそらくプロキシオブジェクトだけが最初にすべて生成される)。
  • ブラウザのバック・フォワードボタンをハンドリングして、適切なページを表示する。

というものと思われる。つまり、PlaceManagerの扱う「ページ」をPlaceと称している。

利用方法

GWTPの自動生成するサンプルコードはDIのせいで流れがわかりにくくなっているが、おおまかな流れとしては以下であると思われる。

Placeの名称を決める

各ページ(Place)の名称を決定する。サンプルコードでは、NameTokensクラスの"main"と"responce"である。

public class NameTokens {
  public static final String main = "main";
  public static final String response = "response";
....

PlaceManagerを作成する

このアプリ専用のPlaceManagerを作成する。これはClientPlaceManagerというクラスになる。 Placeへの移動要求はPlaceRequestオブジェクトで行うのだが、デフォルトのPlace用のリクエストを作成しておく。 以下のコードでは、GInjectorを使って、デフォルトPlaceの名称が注入されるようになっている。

public class ClientPlaceManager extends PlaceManagerImpl {

  private final PlaceRequest defaultPlaceRequest;

  @Inject
  public ClientPlaceManager(final EventBus eventBus,
      final TokenFormatter tokenFormatter,
      @DefaultPlace final String defaultPlaceNameToken) {
    super(eventBus, tokenFormatter);
    this.defaultPlaceRequest = new PlaceRequest(defaultPlaceNameToken);
  }

  @Override
  public void revealDefaultPlace() {
    revealPlace(defaultPlaceRequest, false);
  }
}

Placeの実装を作成する

Placeの名称とそれを管理するオブジェクトを作成したので、次にPlaceの実装を作成する。 この実体は、Presenter(MVPのP)オブジェクトになるのだが、このオブジェクトは非常に大きくなる可能性があるため、 実際には、そのプロキシを作成してPlaceの名称をつけておく。"main"については、MainPagePresenterクラスの内部クラスであるMyProxyになる。

   ...
  @ProxyStandard
  @NameToken(NameTokens.main)
  public interface MyProxy extends ProxyPlace<MainPagePresenter> {
  }
   ...

"response"についても同じ、ResponsePresenterクラスのMyProxyになる。

   ...
  @ProxyStandard
  @NameToken(NameTokens.response)
  public interface MyProxy extends ProxyPlace<ResponsePresenter> {
  }
   ...

@ProxyStandardについては詳細不明。通常はこれをつけておけばよいようだ。

ワイヤリングを行う

gwtpでは標準でGINを使用しているので、このワイヤリングを行う。

ClientModule.java

....
public class ClientModule extends AbstractPresenterModule {

  @Override
  protected void configure() {
    install(new DefaultModule(ClientPlaceManager.class));

    bindPresenter(MainPagePresenter.class, MainPagePresenter.MyView.class,
        MainPageView.class, MainPagePresenter.MyProxy.class);

    bindConstant().annotatedWith(DefaultPlace.class).to(NameTokens.main);

    bindPresenter(ResponsePresenter.class, ResponsePresenter.MyView.class,
        ResponseView.class, ResponsePresenter.MyProxy.class);
  }
}

ClientGinjector.java

...
@GinModules({ DispatchAsyncModule.class, ClientModule.class })
public interface ClientGinjector extends Ginjector {

  EventBus getEventBus();

  PlaceManager getPlaceManager();

  Provider<MainPagePresenter> getMainPagePresenter();

  Provider<ResponsePresenter> getResponsePresenter();
}