Activity handlers don't get removed

1.7k views Asked by At

I'm trying to get up to speed on using GWT Activities and Places. I'm testing with some source code originally found on this good blog post.

I'm finding the Handlers that get added during bind() never seem to removed. My little understanding of the Activity javadoc had me thinking they should get automagically removed by the time the Activity's onStop() method is invoked.

All event handlers it registered will have been removed before this method is called.

But each time I click a button the corresponding handler is called n+1 times.

What am I missing? Please let me know if there is more info I can provide.

Here's a relevant snippet from the code:

public class ContactsActivity extends AbstractActivity {

private List<ContactDetails> contactDetails;
private final ContactsServiceAsync rpcService;
private final EventBus eventBus;
private final IContactsViewDisplay display;
private PlaceController placeController;

public interface IContactsViewDisplay {
    HasClickHandlers getAddButton();
    HasClickHandlers getDeleteButton();
    HasClickHandlers getList();
    void setData(List<String> data);
    int getClickedRow(ClickEvent event);
    List<Integer> getSelectedRows();
    Widget asWidget();
}

public ContactsActivity(ClientFactory factory) {
    GWT.log("ContactActivity: constructor");

    this.rpcService = factory.getContactServiceRPC();
    this.eventBus = factory.getEventBus();
    this.display = factory.getContactsView();
    this.placeController = factory.getPlaceController();
}

@Override
public void start(AcceptsOneWidget container, EventBus eventBus) {
    GWT.log("ContactActivity: start()");

    bind();
    container.setWidget(display.asWidget());
    fetchContactDetails();

}

public void bind() {

    GWT.log("ContactActivity: bind()");

    display.getAddButton().addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            GWT.log("Add button clicked");
            ContactsActivity.this.placeController.goTo(new NewContactPlace(""));
        }
    });

    display.getDeleteButton().addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            GWT.log("ContactActivity: Delete button clicked");
            deleteSelectedContacts();
        }
    });

    display.getList().addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            GWT.log("ContactActivity: List clicked");
            int selectedRow = display.getClickedRow(event);

            if (selectedRow >= 0) {
                String id = contactDetails.get(selectedRow).getId();
                ContactsActivity.this.placeController.goTo(new EditContactPlace(id));
            }
        }
    });
}
2

There are 2 answers

2
Jason Terk On BEST ANSWER

Events registered via. the EventBus passed to AbstractActivity#start() will be unregistered by the time onStop() is called. The event handlers registered in the above bind() method, however, are not registered via the EventBus and are not visible to the abstract base class. You need to unregister them yourself:

public class ContactsActivity extends AbstractActivity {
  private List<HandlerRegistration> registrations = new ArrayList();

  private void bind() {
    registrations.add(display.getAddButton().
      addClickHandler(new ClickHandler() { ... }));
    registrations.add(display.getDeleteButton().
      addClickHandler(new ClickHandler() { ... }));
    registrations.add(display.getList().
      addClickHandler(new ClickHandler() { ... }));
  }

  @Override
  public void onStop() {
    for (HandlerRegistration registration : registrations) {
      registration.removeHandler();
    }

    registrations.clear();
  }
}
0
Jim ReesPotter On

I found it best to handle registration in the view - make it responsible for only keeping one click hander active for each button.

Instead of:

class View {
    Button commitButton;

    public HasClickHandlers getCommit () {return commitButton;}
}

..and link to this in the Activity:

view.getCommit.addClickHandler(new Clickhandler()...

Do this in the View:

    class View {
        private Button commitButton;        
        private HandlerRegistration commitRegistration = null;

        public void setCommitHandler (ClickHandler c) {
            commitRegistraion != null ? commitRegistration.removeRegistration ();
            commitRegistration = commitButton.addClickHandler (c);
        }
    }

And the Activity:

view.setCommitHandler (new ClickHandler () ...

Hope that helps.