GWTのPlaceとActivity
作成中のアニメ特化アンテナサイト
ブラウザの履歴に残るようにする
GWTはAjaxでクリックイベントを処理するので、ブラウザの履歴に残らない。
ただ、通常の感覚としては、リンククリックしたらブラウザの戻るで戻ってほしい。
そこで、GWTでは、PlaceとActivityというクラスでこの仕組みを提供している。
UI
anchor1とanchor2を用意し、anchor1がクリックされたらHello anchor1、anchor2がクリックされたらHello anchor2と表示されるサイトを作成する。
このクリックをブラウザバックに対応させる。
UiBinder
anchor1とanchor2を追加し、Labelに結果を表示する。
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <ui:style> </ui:style> <g:HTMLPanel> <g:VerticalPanel> <g:Anchor text="anchor1" ui:field="anchor1" /> <g:Anchor text="anchor2" ui:field="anchor2" /> <g:Label ui:field="label" /> </g:VerticalPanel> </g:HTMLPanel> </ui:UiBinder>
HelloViewImplコンストラクタはHelloの後に続く文字列を第2引数でとる。
HelloPlaceコンストラクタは第1引数にtokenをとり、この文字列がURLに追加される。
ここでは、押されたリンクに依存し、anchor1もしくはanchor2を指定する。
public class HelloViewImpl extends Composite { private static HelloViewImplUiBinder uiBinder = GWT .create(HelloViewImplUiBinder.class); interface HelloViewImplUiBinder extends UiBinder<Widget, HelloViewImpl> { } @UiField Anchor anchor1; @UiField Anchor anchor2; @UiField Label label; private PlaceController placeController; public HelloViewImpl(PlaceController placeController, String text) { initWidget(uiBinder.createAndBindUi(this)); this.placeController = placeController; label.setText("Hello " + text); } @UiHandler("anchor1") void onAnchor1Click(ClickEvent event) { placeController.goTo(new HelloPlace(anchor1.getText())); } @UiHandler("anchor2") void onAnchor2Click(ClickEvent event) { placeController.goTo(new HelloPlace(anchor2.getText())); } }
Place
PlaceはURLに追加されるトークンを規定する。
具体的には#HelloPlace:tokenが追加される。TokenizerのgetPlace(String token)の第1引数tokenはコロン以降の文字列が入る。
public class HelloPlace extends Place { private String token; public HelloPlace(String token) { this.token = token; } public String getToken() { return token; } public static class Tokenizer implements PlaceTokenizer<HelloPlace> { @Override public String getToken(HelloPlace place) { return place.getToken(); } @Override public HelloPlace getPlace(String token) { return new HelloPlace(token); } } }
Activity
ActivityはPlace(トークン)とUI(UiBinder)を繋ぐ。
startのオーバーライドで、HelloViewImplをインスタンス化し、containerWidgetにsetWidgetする。
containerWidgetはActivityManagerのsetDisplayで指定したWidgetになる。
public class HelloActivity extends AbstractActivity { private String token; private PlaceController placeController; public HelloActivity(HelloPlace place, PlaceController placeController) { this.token = place.getToken(); this.placeController = placeController; } @Override public void start(AcceptsOneWidget containerWidget, EventBus eventBus) { containerWidget.setWidget(new HelloViewImpl(placeController, token)); } }
また、Activityを利用するためには、Gwt.gwt.xmlにcom.google.gwt.activity.Activityを追加する必要がある。
<?xml version="1.0" encoding="UTF-8"?> <!-- When updating your version of GWT, you should also update this DTD reference, so that your app can take advantage of the latest GWT module capabilities. --> <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd"> <module rename-to='gwt'> <inherits name='com.google.gwt.user.User' /> <inherits name='com.google.gwt.user.theme.clean.Clean' /> <inherits name="com.google.gwt.activity.Activity" /> <entry-point class='com.ry.gwt.client.Gwt' /> <source path='client' /> <source path='shared' /> </module>
ActivityMapper
ActivityMapperはPlaceとActivityを繋ぐ。
instanceofでplaceのクラスを特定し、適切なActivityのサブクラスを返すようにgetActivityをオーバーライドする。
public class AppActivityMapper implements ActivityMapper { private PlaceController placeController; public AppActivityMapper(PlaceController placeController) { this.placeController = placeController; } @Override public Activity getActivity(Place place) { if (place instanceof HelloPlace) { return new HelloActivity((HelloPlace) place, placeController); } return null; } }
PlaceHistoryMapper
PlaceHistoryMapperはPlaceをHistory(履歴)にマッピングする。
@WithTokenizers({HelloPlace.Tokenizer.class}) public interface AppPlaceHistoryMapper extends PlaceHistoryMapper { }
エントリーポイント
エントリーポイントで、これらの要素を繋ぐ。
Activityのstartメソッドの第1引数AcceptsOneWidget containerWidgetはここで指定したSimplePanelになる。
public class Gwt implements EntryPoint { @Override public void onModuleLoad() { SimplePanel appWidget = new SimplePanel(); RootPanel.get().add(appWidget); EventBus eventBus = new SimpleEventBus(); PlaceController placeController = new PlaceController(eventBus); // Start ActivityManager for the main widget with our ActivityMapper ActivityMapper activityMapper = new AppActivityMapper(placeController); ActivityManager activityManager = new ActivityManager(activityMapper, eventBus); activityManager.setDisplay(appWidget); // Start PlaceHistoryHandler with our PlaceHistoryMapper AppPlaceHistoryMapper historyMapper = GWT.create(AppPlaceHistoryMapper.class); PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper); historyHandler.register(placeController, eventBus, new HelloPlace("anchor1")); // Goes to the place represented on URL else default place historyHandler.handleCurrentHistory(); } }