As we worked through enhancing the way events were handled in Gwt-Platform, we came across one constatation, no common pattern was used or encouraged. This post addresses this issue and offers a little tutorial about how to create custom events in Gwt-Platform.
First of all, an event contains two major parts: the Event class itself and an Handler. Those two parts can either sit in different files or be included in the same file, with the Handler nested inside the Event. The second approach is our favorite since Handler is an interface related to an event. Also, it can be done in a few lines and reduce the total number of files.
Give that, here’s how we write our events:
public class ShowMessageEvent extends GwtEvent<ShowMessageEvent.ShowMessageHandler> { public interface ShowMessageHandler extends EventHandler { void onShowMessage(ShowMessageEvent event); } private static Type<ShowMessageHandler> TYPE = new Type<ShowMessageHandler>(); public static void fire(HasEventBus source, String message) { if (TYPE != null) { source.fireEvent(new ShowMessageEvent(message)); } } public static Type<ShowMessageHandler> getType() { return TYPE; } private final String message; public ShowMessageEvent(final String message) { this.message = message; } @Override public Type<ShowMessageHandler> getAssociatedType() { return TYPE; } public String getMessage() { return message; } @Override protected void dispatch(ShowMessageHandler handler) { handler.onShowMessage(this); } }
Note here the static fire method. This is a convenient static factory method that let’s you fire an event without having to manually instantiate a ShowMessageEvent class. Using these methods is recommended rather than calling directly fireEvent. Also, the first parameter of this method is not the event bus itself, but rather the source. Passing in your presenter as the first parameter will make sure that the event is attached to the real source that triggered it. Using HasEventBus rather than GWT’s HasHandlers increases the type safety of GWTP, ensuring you never fire into a widget an event that was supposed to go on the bus.
Now that we have all the scaffolding for the event, it’s time to figure out how to use it. In Gwt-Platform every presenter implements HasEventBus so they all have the ability to fire events. The best practice approach is to simply use the static fire method of your event. In the above example this would be ShowMessageEvent.fire(this, “Hello world!”);. Some situations will require you to fire events from an object that doesn’t have access to fireEvent(). In this case, the best practice is to inject the EventBus, implement HasEventBus, and relay the call to fireEvent:
public abstract class MyCustomCallback<T> implements AsyncCallback<T>, HasEventBus { @Inject private static EventBus eventBus; @Override public void onFailure(Throwable caught) { ShowMessageEvent.fire(this, "Oops! Something went wrong!"); } @Override public void fireEvent(GwtEvent<?> event) { eventBus.fireEvent(this, event); } }
In this case we have used static injection to provide the EventBus (don’t forget to requestStaticInjection in your Gin module!). This is because AsyncCallback classes do not typically participate in dependency injection. If your class does participate in dependency injection then you should use constructor injection. The goal of this pattern is to ensure that event sources are correctly tracked. Since the callback implements HasEventBus it will set itself as the source of the event. More importantly, every class that extends this abstract class will be able to fire any event and set itself as the source.
Now, how do we listen to events travelling on the bus? If you’re listening from a presenter, the prefered way is to use addRegisteredHandler(eventType, eventHandler);. This method not only registers a handler on the event bus, it also makes sure that every registered handler is correctly unregistered when the presenter is unbound. If you are not within a presenter, inject the EventBus and call eventBus.addHandler(eventType, eventHandler);. It is customary to use an anonymous inner class as an eventHandler, for example:
public abstract class MyPresenter extends PresenterImpl<MyPresenter.MyView, MyPresenter.MyProxy> { ... @Override public void onBind() { super.onBind(); addRegisteredHandler( ShowMessageEvent.getType(), new ShowMessageHandler() { @Override void onShowMessage(ShowMessageEvent event) { getView().displayMessage( event.getMessage() ); } } ); } }
But you can also use the following pattern:
public abstract class MyPresenter extends PresenterImpl<MyPresenter.MyView, MyPresenter.MyProxy> implements ShowMessageHandler { ... @Override public void onBind() { super.onBind(); addRegisteredHandler( ShowMessageEvent.getType(), this ); } @Override void onShowMessage(ShowMessageEvent event) { getView().displayMessage( event.getMessage() ); } }
I hope this post will help you design your own events, but in any case feel free to leave comments or ask questions! In a future article we will discuss how you can automatically generate most of the boilerplate using GWTP’s annotation processing classes contributed by Brendan Doherty. We will also discuss the use of the @ProxyEvent annotation and how it differs from the events described above.
Thanks for your great post Christian. Maybe you should also mention the annotation processing implemented by Brendan which saves a lot of boilerplate (in relation to http://code.google.com/p/gwt-platform/wiki/BoilerplateGeneration). It’s a great feature.
@GenEvent
public class ShowMessage {
String message;
}
should be enough instead of ShowMessageEvent 😉 greetings!
Yeah, well we wanted to make two articles, we don’t want to enforce anyone to use our annotation processing tool 😀
There’s also more to his tool, so I’ll make sure to talk about all features 🙂
Cheers,
Hi, although this post is quite old now, I hope that comments are still read:
I have two presenters which are handlers for the same event type. At one time, only one presenter is displayed, the other is hidden.
I have registered the handlers as described above: with addRegisteredHandler() . However, unlike expected (quote “it also makes sure that every registered handler is correctly unregistered when the presenter is unbound”) the event is always dispatched to both presenters. I also could not find any code which unregisters event handlers triggered by Presenter lifecycle methods.
Did I misunderstood something
Comments are always read, I get notified when there’s new ones 😛
Did you specifically call unbind? Presenters are never unbound unless you do it manually. They are singletons that lives and die with the application unless you specify otherwise.
Oh, really quick indeed 😉
No, I did not call unbind(), probably I just mixed up the lifecycle state names. However, if I do not want to unbind, what would you suggest to do to achieve that the event is only dispatched to the displayed presenter without manually unregistering? And if only manual unregistering is possible, which lifecycle method would you recommend to do this?
Normally only a presenter that has a handler to that specific event would receive it. The EventBus only calls the handler that is registered with the event.
That being said, if your concern is about the presenter receiving event when it’s not visible, you could call unbind in the onHide method. Afterward when it’ll get displayed again, onBind() will be called again.
Probably a comment-tree-depth constraint 🙂
Yes, I will follow your advice although it does have a smell that I do something for it that usually is not done (unbinding a presenter).
Thanks for your help and your MVP library at all,
Best regards,
Rainer.
Bonjour,
J’ai dans mon “MainPagePresenter” contient trois presenters/slots: header, content et footer. Le header contient différents onglets pour choisir les différentes pages (et donc changer le contenu principal). Je veux changer le style de ces onglets pour indiquer la page active. Est-ce que ce serait adéquat d’utiliser le méchanisme décrit ici pour faire cela en faisant le fire sur le onreset() des presenters de contenu et de mettre le handler correspondant dans le presenter du header pour aller changer le style ?
Si le header est un presenterwidget, vous pouvez effectivement utiliser onReset et utiliser le PlaceManager pour aller chercher la place active. C’est ce que je fais à plusieurs occasions et même, si chacun des liens sont des presenters widgets, vous pourriez les laisser ce gérer d’eux même sans interaction de la part du header parent.
La deuxième méthode est souvent ce que j’utilise quand je fais des tab / tab dynamique.
Hello,
how can i fire events form server side? is there any possibility to use gwteventservice with gwt-platform?
Yes it is, another solution would be to use the great Errai-Bus!
Can you give me a clue how?
unfortunately, I do not have any. Stackoverflow may be a good place to ask the question as I’ve never tryed those tools. GWTP let you use whatever communication based system you wish to use, it shouldn’t be a problem.