使用GWT和Gin的交叉活动参考

时间:2011-04-29 03:30:03

标签: gwt dependency-injection mvp guice gin

我有一个使用活动和地点的GWT MVP应用程序。这是受到Mauro Bertapelle的样本(this thread)的启发,显然基于Thomas Broyer的一些工作。

问题在于:我让LoginActivity进行RPC调用,为了成功登录,返回一个User。该用户具有角色(例如,管理员,普通用户,访客)。包括NavigatorView在内的多个视图和活动依赖于此角色来显示或执行的操作。如何将此User实例提供给其他活动?

我没有ClientFactory; inject(Gin)用于实例化ActivityProviders中提供我的Activities / Presenters的Views,并将ActivityProviders注入到我的ActivityMapper中。所以这可能会减少到一个杜松子酒问题:如何在需要的地方获得用户参考?这似乎与this SO question类似,关于MVP中的全局引用。

考虑我一个杜松子酒新手,这是我第一次尝试使用它。我猜测有一种“杜松子酒方式”可以实现这一点,但我不知道杜松子酒能够知道最好的方法(如果应该使用杜松子酒)。

非常感谢。

编辑1:尽管我在搜索SO以寻找类似问题时尽了最大的努力,但我发现this question与我的几乎完全相同(是用于查找“相关”链接的SO算法比搜索更好?)。我认为David的Gin回答是正确的。

我不认为EventBus解决方案是可行的。我正在关注Google guidelines,其中涉及在每次Place更改时实例化Activity,因此单个事件本身是不够的。

2 个答案:

答案 0 :(得分:3)

我在服务器端与Guice一起使用的东西,在客户端也能正常工作,就是绑定到自定义Provider。但是,在您的情况下,您必须使提供程序成为单例并从RPC回调中将值推入其中(而不是从某些上下文中提取它)。 您首先需要一个特定的提供者:

@Singleton
public class CurrentUserProvider implements Provider<User> {
  private User currentUser;

  public User get() { return currentUser; }
  public void setCurrentValue(User currentUser) {
    this.currentUser = currentUser;
  }
}

您将User绑定到提供商:bind(User.class).toProvider(CurrentUserProvider.class) 在您的RPC回调中,您将注入一个CurrentUserProvider,因此您可以setCurrentValue,但在其他任何地方注入Provider<User>以保留CurrentUserProvider作为实施细节。对于非常短暂的对象,您可以直接注入User值而不是Provider<User>

如果您需要通知对象更改值,您可以在全局事件总线上调度事件。

或者,您可以始终使用具体的CurrentUserProvider类型(不再需要实现Provider)并可能使其成为HasValueChangeHandlers,以便您可以在其上注册侦听器而不是在事件总线上(但你必须在你的活动'onStoponCancel之后清理自己,以避免内存泄漏,而如果你在事件上注册处理程序,它会自动处理onStart)中的公共汽车。

(如果你问我,我宁愿尽可能在应用程序内部进行身份验证)

答案 1 :(得分:1)

我对最近的一个项目有类似的要求。

当我从登录(或注销)RPC获得回复时,我在EventBus上发送自定义AuthenticationEvent。所有对此感兴趣的活动都会收听此活动。 AuthenticationEvent具有对AppUser对象的引用,如果用户刚刚注销,则该引用为null。 AppUser包含所有必要的数据(特权,组等),以便活动可以检查它并对其采取行动。

关于全局引用:您可以使用提供所需数据的静态方法的类。此类在内部保存对所需实例的单例引用。在我的例子中,我有静态方法AppUtils.getCurrentUser()。在内部,它包含对AppUser的引用,并且还侦听AuthenticationEvent以设置/重置此字段。

作为旁注:不要依赖客户端来强制执行访问限制 - 您应该将RPC servlet分成两组:public和private。公共可以被任何人访问(这基本上是登录/注销RPC和一些其他公共信息RPC),而私有RPC要求用户进行身份验证。可以为每个路径/ servlet设置访问限制:http://code.google.com/appengine/docs/java/config/webxml.html#Security_and_Authentication

<强>更新

  1. 正如您所指出的,在此设置中不建议使用静态方法的类,因为它不可替换,这会阻止测试(这是使用GIN的重点)。

  2. 解决方案是将一个包含全局变量(AppUtils)的实用程序类注入需要全局变量的活动中。 AppUtils应该在GIN配置中声明为singleton,因为一个实例足以满足整个应用程序。

  3. 如果您想延迟依赖项的初始化(AppUtil是依赖项),那么使用Provider只是一个问题。由于AppUtils是整个应用程序的单例,因此将其初始化为懒惰是没有意义的。

  4. 有时你会遇到屏幕上显示多个活动的情况(在我的例子中是MenuBar和InfoBar)。在这种情况下,当用户登录时,您需要一种方法来通知他们更改。使用EventBus。