【问题标题】:Cross-Activity references using GWT with Gin使用 GWT 和 Gin 的跨活动参考
【发布时间】:2011-08-15 05:07:11
【问题描述】:

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

问题是:我让 LoginActivity 进行了 RPC 调用,如果成功登录,它会返回一个用户。此用户具有角色(例如,管理员、普通用户、访客)。包括 NavigatorView 在内的多个视图和活动依赖于这个角色来显示或执行。如何将此用户实例获取到其他活动?

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

假设我是杜松子酒新手,这是我第一次尝试使用它。我猜有一种“杜松子酒方式”可以实现这一点,但我对杜松子酒的了解还不够,无法知道最好的方法(如果应该使用杜松子酒的话)。

非常感谢。

编辑 1: 尽管我尽了最大努力在 SO 上搜索类似的问题,但我还是找到了与我的几乎相同的 this question(查找“相关”链接的 SO 算法是否优于搜索?)。我认为大卫对杜松子酒的回答是正确的。

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

【问题讨论】:

    标签: gwt dependency-injection mvp guice gwt-gin


    【解决方案1】:

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

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

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

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

    更新:

    1. 正如您所指出的,在此设置中不建议使用具有静态方法的类,因为它不可替换并且这会妨碍测试(这是使用 GIN 的全部要点)。

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

    3. 要不要使用Provider只是一个问题,如果你想延迟初始化依赖(AppUtil是依赖)。由于 AppUtils 是整个应用程序的单例,因此延迟初始化它是没有意义的。

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

    【讨论】:

    • 嗨,彼得,感谢您的意见。您关于在客户端执行限制的观点很好;我知道这个问题,只是想显示适当的 GUI。有关 EventBus 解决方案的评论,请参阅编辑 1。我想到了全局引用问题的静态解决方案,但有些人认为它的形式不好,而且它似乎不符合应用程序其余部分的“精神”。我有一个 AppController 类,一切都从这里开始,这可能是存储用户以进行静态访问的地方,并且可能会出现这种情况。
    • 您可以拥有一个类,例如 AppUtils,它包含所有全局变量并作为单例注入。
    • 关于事件总线:链接问题中的 OP 询问如何通知有关登录/注销的所有活动。这不是必需的。您应该只通知当时显示的活动。 Activity 启动时会挂接到事件总线,并在隐藏时离开它(这在 GWT 2.1 MVP with Activities 中自动完成)
    • Provider<Type> 本质上用于“延迟注入”。 Provider 不是在创建对象时实例化和注入所有依赖项,而是在需要时(即调用 provider.get() 时)实例化依赖项。这也称为延迟初始化。
    • 因此,如果我理解正确,您最初的建议是创建一个单例 AppUtil 类来保存供全局使用的东西,并在需要的地方注入它。我的 LoginActivity 将拥有它来设置经过身份验证的用户,而我的其他活动将拥有它来访问用户。
    【解决方案2】:

    我在服务器端与 Guice 一起使用并且在客户端也可以正常工作的东西是绑定到自定义提供程序。但是,在您的情况下,您必须使提供者成为单例并从您的 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&lt;User&gt; 以保留 CurrentUserProvider 作为实现细节。对于非常短暂的对象,您可以直接注入 User 值而不是 Provider&lt;User&gt;

    如果你需要通知对象值的变化,你可以在全局事件总线上调度一个事件。

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

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

    【讨论】:

    • 哦,它看起来很像您已经链接到的stackoverflow.com/questions/4629777/… 的答案!
    • 感谢您对杜松子酒的这些见解(以及更多有用的博客文章)。说实话,我怀疑杜松子酒是否值得麻烦——也许当我理解得更好时,我会被说服。顺便说一句,我的问题似乎让人们相信我正在做客户端身份验证。我不是。我正在做客户端配置
    • 那为什么不使用dynamic host page呢?它将替换您的 RPC 调用并可以立即注入该值,因为它在您创建 Ginjector 并注入您的对象时可用。
    • 好吧,在您提到之前,我从未听说过动态主机页面。感谢您的提示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    • 2012-03-13
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    相关资源
    最近更新 更多