GWT - MVP 事件总线。多个处理程序被创建

3

我正在处理一个大型的应用程序,但是在最佳实践方面遇到了一些问题。

每当用户导航到我们的客户编辑页面时,都会创建一个新的presenter,并设置一个view。客户编辑有一个主presenter和一个主视图。在主视图中还有子视图,这些子视图由主presenter的sub presenter使用。在子presenter中,我在事件总线上注册事件处理程序。

问题是,当用户第二次导航到联系人编辑器时,presenter被再次创建,并且那些事件被再次注册。现在,当事件发生时,它会被处理两次,每个presenter实例一次。

presenter没有被变量持有,但子视图被主视图引用。这种引用是否会使事件处理程序无法被移除?我原本以为,如果该对象被垃圾回收,事件处理程序将被删除。如果不是这种情况,那么我应该从事件总线中注销这些事件处理程序吗?

更新: presenter没有被垃圾回收。 如果我修改代码以删除所有对这些presenter的引用,它们是否会被收集,因此事件处理程序会被移除?

2个回答

5
ResettableEventBus是专门为此设计的 - 不是给Presenter一个全局事件总线,而是将该事件总线封装在可重置版本中。然后,当关闭该Presenter时,谁给它提供了该事件总线就会重置它,从而清理它可能添加的所有处理程序。
这就是GWT的Activity/Place框架中管理活动以防止泄漏的方式。
另一个选择是为每个Presenter提供像“stop()”或“release()”这样的方法,表示它已经完成,应该在自己之后进行清理 - 取消正在进行的RPC调用、移除对话框、取消事件处理程序。与上面一样,Activity API有一个方法来指示它即将停止,并且已经停止并应该清理。
提供两者使得不使用全局事件总线很容易避免错误,并仍然提供更细粒度问题的钩子(长时间运行的RPC调用),但任何一种解决方案都可以解决问题。

ResettableEventBus听起来在我的情况下会很有用。问题是如何确定何时关闭presenter。不幸的是,原始开发人员没有使用Activity/Place框架,所以一切都是自定义的。我将深入挖掘代码,看看是否有某种方法可以告诉我何时释放特定的presenter。 - aglassman
定制化并不是坏事 - 我不经常使用activity/place,而是更倾向于使用更具体的方法。关于必须决定何时结束presenter, 你说得对 - 这也是问题的要点,对吧?当它结束时,强制释放它所持有的资源。如果你不知道它是否已经结束,那么它怎么可能知道该释放那些事件处理程序呢? - Colin Alworth
感谢您的建议,但我最终使用了单例模式来重用同一个Presenter。这样做更容易,因为我不必清理事件处理程序。 - aglassman

1
事件处理程序是单独的对象实例,它们被设置并存储在EventBus内的某种集合中。您的Presenter只需创建它们并将它们传递给EventBus,因此处理程序仍然在Presenter的生命周期之外被引用(这就是它们保持运行的原因)。Presenter可能没有被垃圾回收,因为处理程序可能仍然引用它们或它们的字段。
每次创建新的Presenter都会再次添加处理程序,正如您所发现的那样,因此解决方案要么在实例化新的Presenter之前清除现有的处理程序,要么跟踪它们并在已经添加时不添加新的处理程序。
我采取的方法是重用屏幕级别的View/Presenter实例,并在重新进入时重置它们的状态。这也有助于提高性能。Presenter还跟踪它们添加到EventBus的所有处理程序的HandlerRegistration实例。
我不知道Colin提到的ResettableEventBus,但那听起来也是一个不错的解决方案。

由于应用程序的设计方式,我可以将所提到的Presenter设置为单例。这样它只会被创建一次。在GWT中使用这种设计模式是否可行? - aglassman
"可接受的"是一个客观术语 :) 如果您想这样做,也可以使用GIN创建Presenter的单例实例。 - Jonathan
我尝试了单例模式,效果非常好。我会研究一下GIN,看看它是否适合在项目中使用。 - aglassman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接