mvp4g LazyPresenter с параметромmultiple=true привязывается дважды

Я использую mvp4g в своем проекте gwt. Для одного из моих докладчиков я использую вариант multiple=true, и я создаю и привязываю докладчиков таким образом:

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

ObjectPresenter расширяет LazyPresenter.

Когда я вызываю первое событие из eventBus, перехваченное ObjectPresenter, снова вызывается метод bind() из LazyPresenter.

bind метод имеет внутри дерева другие методы: createPresenter(); view.createView(); bindView();. В методе bindView из ObjectPresenter я изменяю свое представление, добавляя следующие виджеты. Поскольку метод вызывается дважды (один раз непосредственно мной и один раз фреймворком), некоторые виджеты дублируются.

Я отладил код и обнаружил, что эта часть кода из BaseEventHandler вызывается при вызове события из eventBus:

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;
}

После прямого вызова bind (через mainObject.bind()) связанное свойство в BaseEventHandler не устанавливается в true, поэтому метод bind вызывается снова при вызове первого события.

Я могу установить переменную binded из BaseEventHandler в true в ObjectPresenter, когда метод bind (вызываемый напрямую) завершен, но я не уверен, что это правильный подход...

Не могли бы вы подсказать мне, как бороться с этой проблемой?

Спасибо за вашу помощь.


person kpater87    schedule 18.06.2014    source источник


Ответы (2)


Прежде всего, вопрос, действительно ли вам нужна функция multiple=true. Эта функция предназначена для одновременного использования нескольких экземпляров одного и того же класса докладчика. Если это не ваш случай, не используйте его, потому что вам придется писать много кода, который обычно генерируется mvp4g-framework.

Кроме того, вы никогда не должны вызывать метод bind напрямую.

Если вам нужна множественная функция, вы можете создать обработчик (который расширяет класс BaseHandler). Этот обработчик должен управлять вашими экземплярами докладчика. Код должен содержать список экземпляров вашего презентатора:

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

Чтобы показать новый экземпляр или даже вывести существующий экземпляр на передний план, обработчик должен прослушивать событие (здесь: 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());
}

}

Событие setCurrentObject(Widget widget) сделает ваше представление видимым. Таким образом, ваша оболочка также должна быть реализована как комбинация презентатора/представления, которая должна прослушивать событие setCurrentObject(Widget widget). Используя этот код, вам не нужно вызывать bind-метод.

Я буду использовать этот код в нескольких проектах, и он работает очень хорошо. Кроме того, с этим кодом довольно легко использовать управление историей.

Надеюсь, это поможет.

person El Hoss    schedule 19.06.2014
comment
Я использую addHandler(ObjectPresenter.class), как вы сказали. После создания ведущего я хотел бы добавить его вид на главную панель с помощью view.addWidget(mainObject.getView().asWidget());. Для этого мне нужно привязать весь презентер, используя метод bind, или только представление, используя bindView (да, я использую ленивого ведущего). Проблема в том, что когда я вызываю событие из шины событий, которое перехватывается ObjectPresenter. BaseEventHandler снова вызывает метод bind, поскольку для переменной bineded не задано значение true. Я также изменил вопрос, чтобы сделать его более понятным... - person kpater87; 21.06.2014
comment
Извини за поздний ответ. Я только что проверил ваше предложение, и оно не работает, как я ожидал. Мне нужно установить поля докладчика перед привязкой представления, поэтому я вызываю eventBus.addHandler(ObjectPresenter.class, false); (для параметра привязки установлено значение false). Затем, после настройки полей, я хотел бы связать ведущего, поэтому я вызываю mainObject.bind();, но он не устанавливает для поля binded значение true, поэтому, когда вызывается первое событие, перехваченное ObjectPresenter, презентатор привязывается во второй раз. - person kpater87; 22.07.2014
comment
Пожалуйста, смотрите также мой ответ. - person kpater87; 22.07.2014
comment
Ты не ответил на мой вопрос. Вам действительно нужно более одного экземпляра класса ObjectPresenter? Если нет, не используйте функцию multiple=true. Во-вторых, позвольте фреймворку создать ваше представление и ведущего. Используйте события, чтобы представить ObjectView и добавить его в свою оболочку. В этом случае все будет работать как положено. - person El Hoss; 23.07.2014
comment
у меня такой случай. На моей странице я показываю много панелей для многих объектов (по одной панели на объект). Каждая панель имеет одинаковое поведение, поэтому я реализовал один презентер с параметромmultiple=true. О второй части. Да, фреймворк создаст все для меня, но он привяжет представление до того, как будут установлены поля докладчика. Я хотел бы отложить привязку до того момента, когда все поля будут установлены. - person kpater87; 23.07.2014

Я недостаточно внимательно читал документацию! Я использовал метод eventBus.addHandler(ObjectPresenter.class, false) (с параметром bind), который имеет следующий документ Java.

     /**
     * 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;

Часть, которую я пропустил, это При привязке обработчика вы должны вызвать метод isActivated. Этот метод будет вызываться с eventName и параметрами, установленными на null. и это была моя проблема - я этого не делал!

person kpater87    schedule 22.07.2014
comment
Не изменяйте внутренние флаги фреймворка. Вы получите много неприятностей. - person El Hoss; 23.07.2014
comment
Итак, почему этот метод предоставляется фреймворком, если я не должен его использовать? - person kpater87; 23.07.2014
comment
Для меня это решение работает правильно и согласуется с документацией, поэтому я принимаю его. Тем не менее, спасибо за всю помощь в понимании вопроса. - person kpater87; 23.07.2014
comment
Существует множество методов (и еще один метод bind), которые необходимы и используются фреймворком, а не для общего пользования. Фреймворк имеет четкое представление о том, какой метод, когда вызывать и какой флаг должен быть установлен. Прямой вызов этого метода может повлиять на будущие версии. - person El Hoss; 23.07.2014