mvp4g LazyPresenter with option multiple=true is binded twice

341 Views Asked by At

I am using mvp4g in my gwt project. For one of my presenters I am using option multiple=true and I am creating and binding presenters in that way:

ObjectPresenter mainObject = eventBus.addHandler(ObjectPresenter.class, false);
mainObject.setId(id);
mainObject.bind();
view.addWidget(mainObject.getView().asWidget());

ObjectPresenter extends LazyPresenter.

When I am calling first event from the eventBus that is caught by ObjectPresenter, method bind() of the LazyPresenter is called again.

bind method has inside tree other methods: createPresenter(); view.createView(); bindView();. In the bindView method of the ObjectPresenter I am modifing my view by adding next widgets. Because the method is called twice (once directly by me, and once by framework) some widgets are duplicated.

I've debugged the code and I found that this part of code from BaseEventHandler is called when the event from the eventBus is called:

public final boolean isActivated( boolean passive, String eventName, Object... parameters ) {
    boolean activated = this.activated && pass( eventName, parameters );
    if ( activated ) {
        if ( passive ) {
            return binded;
        } else {
            onBeforeEvent();
            if ( !binded ) {
                bind();
                binded = true;
            }
        }
    }
    return activated;
}

After calling bind directly (by mainObject.bind()) binded property in the BaseEventHandler is not set to true, so bind method is called again when first event is called.

I can set binded variable from the BaseEventHandler to true in the ObjectPresenter when the method bind (called directly) is finished, but I am not sure if it is proper approach...

Could you please give me a hint how to deal with this issue?

Thanks for your help.

2

There are 2 best solutions below

4
On BEST ANSWER

I haven't read documentation carefully enough! I was using method eventBus.addHandler(ObjectPresenter.class, false) (with bind parameter), which has following java doc.

     /**
     * Create a new instance of the handler, bind it only if this option is set to true and add it
     * to event bus. If you decide not to bind the handler at creation, you will have either make
     * sure the handler is displayed only after it handles its first method (otherwise the view is
     * not binded so it seems inactive) or call manualy the bind method.<br/>
     * <br/>
     * When binding the handler, you have to call the isActivated method. This method will be called
     * with eventName and parameters set to null.
     * 
     * @param <T>
     *            type of the handler created
     * @param handlerClass
     *            class of the handler to create
     * @param bind
     *            if true, bind the handler at creation, otherwise do nothing.
     * @return new instance of the handler created
     * 
     * @throws Mvp4gException
     *             thrown if the instance of the handler can not be created by the event bus
     */
    <E extends EventBus, T extends EventHandlerInterface<E>> T addHandler( Class<T> handlerClass, boolean bind ) throws Mvp4gException;

The part I missed is When binding the handler, you have to call the isActivated method. This method will be called with eventName and parameters set to null. and that was my problem - I didn't do this!

5
On

First of all the question, do you really need the multiple=true-featrue. This feature is designed to use sereval instances of the same presenter class at one time. If this is not your case, do not use it, because you'll have to write a lot of code, which is normally generated by the mvp4g-framework.

Also, you should never call the bind-method directly.

If you need the multiple-feature, you can create a handler (which extends BaseHandler-class). This handler should manage your presenter instances. The coding should contain a list of your presenter instances:

  private List<EventHandlerInterface<MyEventBus>> presenters = new ArrayList<EventHandlerInterface<MyEventBus>>();

To show a new instance or even to bring an existing instance to front, the handler should listen to an event (here: eventBus.showObject([someNumber]);:

public void onShowObject(long id) {
  // check if a presenter for that Id already exists
  if (presenters.size() > 0) {
    for (int i = 0; i < presenters.size(); i++) {
      ObjectPresenter presenter = (ObjectPresenter) presenters.get(i);
      if (presenter.getId() == idNr) {
        eventBus.setCurrentObject(presenter.getView().asWidget());
        return;
      }
    }
  }
  // no presenter found, create a new one and add the presetner instance to the list 
  ObjectPresenter mainObject = eventBus.addHandler(ObjectPresenter.class);
  mainObject.setId(id);
  presenters.add(mainObject);
  eventBus.setCurrentObject(mainObject.getView().asWidget());
}

}

The event setCurrentObject(Widget widget) will make your view visible. So your shell must also be implemented as a presenter/view-combination, wich have to listen for the setCurrentObject(Widget widget)-event. Using this code, you don't need to call the bind-method.

I'll use this code in several project and it works really nice. Also, it is quite easy to use history managment with this code.

Hope that helps.