GWT Development with Activities and Places

GWT Development with
Activities and Places
The Activities and Places framework
• a built-in framework for browser history management.
– It builds on GWT's history mechanism
• is introduced in GWT 2.1
• allows you to create bookmarkable URLs within your
– allowing the browser's back button and bookmarks to work as
users expect.
• may be used in conjunction with MVP development,
– though not required.
– Strictly speaking, MVP architecture is not concerned with
browser history management, but Activities and Places may be
used with MVP development as shown in this article.
• An activity
– simply represents something the user is doing.
– contains no Widgets or UI code.
– typically restore state ("wake up"), perform initialization ("set up"), and load a
corresponding UI ("show up").
– can automatically display a warning confirmation
• when the Activity is about to be stopped (such as when the user navigates to a new
– are started and stopped by an ActivityManager associated with a container
• the ActivityManager warns the user before the window is about to be closed.
• A place
– is a Java object
• The object represents a particular state of the UI.
– can be converted to and from a URL history token by defining a PlaceTokenizer
for each Place,
• see GWT's History mechanism)
– GWT's PlaceHistoryHandler automatically updates the browser URL
corresponding to each Place in your app.
2. fire
1. initiates navigation to
a new Place, e.g., place2
User Activity1
State of
User Activity2
Managed by
•Activity2 := Get the activity
corresponding to place2
Notify current_activity
If current_activity is OK
Start activity2
3. Listen to/updates
State of
Moving parts in a GWT 2.1
• A view
– is simply the part of the UI
– is associated with an Activity.
– is defined by an interface,
• Interface allows multiple view implementations based on client
characteristics (such as mobile vs. desktop)
• Interface facilitates lightweight unit testing by avoiding the timeconsuming GWTTestCase.
• There is no View interface or class in GWT which views
must implement or extend;
– however, GWT 2.1 introduces an IsWidget interface that is
implemented by most Widgets as well as Composite.
– useful for views to extend IsWidget if they do in fact provide a
The corresponding view implementation extends Composite, which keeps
dependencies on a particular Widget from leaking out.
The Presenter interface and setPresenter method allow for bi-directional
communication between view and presenter, which simplifies interactions involving
repeating Widgets and also allows view implementations to use UiBinder with
@UiHandler methods that delegate to the presenter interface.
• Widget creation
– involves DOM operations,
– are relatively expensive to create.
• It is good practice to
– make them reusable,
– How? via a view factory, which might be part of a larger ClientFactory.
• A ClientFactory
– is not required to use Activities and Places ,however
– it is helpful to use a factory or dependency injection framework
• like GIN to obtain references to objects needed throughout your application
like the event bus.
• Our example
– uses a ClientFactory to provide an EventBus, GWT PlaceController, and
view implementations.
Another advantage of using a
• Deferred binding
– to use different implementation classes based on
user.agent or other properties.
• For example, you might
– use a MobileClientFactory to provide different
view implementations than the default
– How? instantiate your ClientFactory with
GWT.create in onModuleLoad()
• Activity classes
– implement
– extend
AbstractActivity, (for
• provides default
implementations of
all required methods.
• Example
– simply says hello to a
named user:
HelloActivity obtain HelloPlace’ states
obtain a reference to the HelloView as well
as the EventBus and PlaceController
The first thing to notice is that HelloActivity makes reference to HelloView, which is a view
interface, not an implementation. One style of MVP coding defines the view interface in the
presenter. This is perfectly legitimate; however, there is no fundamental reason why an Activity and
it's corresponding view interface have to be tightly bound together. Note that HelloActivity also
implements the view's Presenter interface. This is used to allow the view to call methods on the
Activity, which facilitates the use of UiBinder as we saw above.
The HelloActivity constructor takes two arguments: a HelloPlace and the ClientFactory. Neither is
strictly required for an Activity. The HelloPlace simply makes it easy for HelloActivity to obtain
properties of the state represented by HelloPlace (in this case, the name of the user we are
greeting). Accepting an instance of a HelloPlace in the constructor implies that a new HelloActivity
will be created for each HelloPlace. You could instead obtain an activity from a factory, but it's
typically cleaner to use a newly constructed Activity so you don't have to clean up any prior state.
Activities are designed to be disposable, whereas views, which are more expensive to create due to
the DOM calls required, should be reusable. In keeping with this idea, ClientFactory is used by
HelloActivity to obtain a reference to the HelloView as well as the EventBus and PlaceController.
The start method is invoked by the ActivityManager and sets things in motion. It updates the view
and then swaps the view back into the Activity's container widget by calling setWidget.
The non-null mayStop() method provides a warning that will be shown to the user when the
Activity is about to be stopped due to window closing or navigation to another Place. If it returns
null, no such warning will be shown.
Finally, the goTo() method invokes the PlaceController to navigate to a new Place. PlaceController in
turn notifies the ActivityManager to stop the current Activity, find and start the Activity associated
with the new Place, and update the URL in PlaceHistoryHandler.
• One Activity -> one Place.
– URL -> activity
• A Place
– extends
– must have an associated PlaceTokenizer
• PlaceTokenizer knows how to serialize the Place's state to a URL token.
– By default, the URL
• consists of the Place's simple class name (like "HelloPlace") followed by a
colon (:) and the token returned by the PlaceTokenizer.
• It is convenient (though not required) to declare the PlaceTokenizer
as a static class inside the corresponding Place.
– However, you need not have a PlaceTokenizer for each Place.
– Many Places in your app might not save any state to the URL, so they
could just extend a BasicPlace which declares a PlaceTokenizer that
returns a null token.
• PlaceHistoryMapper
– Declares all the Places available in your app
– Is the link between your PlaceTokenizers and GWT's PlaceHistoryHandler that
synchronizes the browser URL with each Place.
• You create an interface
– that extends PlaceHistoryMapper and uses the annotation @WithTokenizers
to list each of your tokenizer classes
• At GWT compile time,
– GWT generates (see PlaceHistoryMapperGenerator) a class based on your
interface that extends AbstractPlaceHistoryMapper.
• For more control of the PlaceHistoryMapper,
– use the @Prefix annotation on a PlaceTokenizer to change the first part of the
URL associated with the Place.
• For even more control,
– implement PlaceHistoryMapperWithFactory and provide a TokenizerFactory
that, in turn, provides individual PlaceTokenizers.
• Maps
– each Place to its
corresponding Activity.
• It must implement
– ActivityMapper,
• Have code like
– "if (place instanceof
SomePlace) return new
• Must know about the
– so it can provide it to
activities as needed
Putting it all together
The ActivityManager
– keeps track of all Activities running within the context of one container
– listens for PlaceChangeRequestEvents
– notifies the current activity when a new Place has been requested.
– If the current Activity allows the Place change (Activity.onMayStop() returns
null) or the user allows it (by clicking OK in the confirmation dialog),
• the ActivityManager discards the current Activity and starts the new one.
• In order to find the new one, it uses your app's ActivityMapper to obtain the Activity
associated with the requested Place.
• PlaceController
– initiates navigation to a new Place and is responsible for warning the user
before doing so.
• PlaceHistoryHandler
– provides bi-directional mapping between Places and the URL.
– Whenever your app navigates to a new Place, the URL will be updated with
the new token representing the Place so it can be bookmarked and saved in
browser history.
– Likewise, when the user clicks the back button or pulls up a bookmark,
PlaceHistoryHandler ensures that your application loads the corresponding
How to navigate
• To navigate to a new Place in your application,
– call the goTo() method on your PlaceController.
– This is illustrated above in the goTo() method of HelloActivity.
PlaceController warns the current Activity that it may be stopping (via
a PlaceChangeRequest event) and once allowed, fires a
PlaceChangeEvent with the new Place.
– The PlaceHistoryHandler
• listens for PlaceChangeEvents and updates the URL history token accordingly.
– The ActivityManager also
• listens for PlaceChangeEvents and uses your app's ActivityMapper to start the
Activity associated with the new Place.
• Rather than using PlaceController.goTo(), you can also
– create a Hyperlink containing the history token for the new Place
• by calling your PlaceHistoryMapper.getToken().
– When the user navigates to a new URL (via hyperlink, back button, or
• PlaceHistoryHandler catches the ValueChangeEvent from the History object
and calls your app's PlaceHistoryMapper to turn the history token into its
corresponding Place.
• It then calls PlaceController.goTo() with the new Place.

similar documents