【问题标题】:using GIN in GWT Activities在 GWT 活动中使用 GIN
【发布时间】:2012-03-29 11:45:32
【问题描述】:

我的每个活动都需要一个相应的单例视图实现。将它们注入活动的最佳策略是什么?

  1. 构造函数注入 Activity 构造函数是从 ActivityMapper 的 getActivity() 调用的。 ctor 已经有一个参数(一个 Place 对象)。我必须创建 ActivityMapper 并注入所有可能的视图。不好...

  2. 方法注入 - “这样注释的函数会在构造函数执行后自动执行。”(GWT in Action,第 2 版)好吧, “在执行ctor之后”显然不够快,因为当调用Activity的start()方法并且我得到一个NPE时,视图(或以这种方式注入的RPC服务)仍​​未初始化。

    李>
  3. 在 Activity 的 ctor 中使用 GWT.create 构造注入器。没用,因为它们不再是单例了。

【问题讨论】:

    标签: gwt dependency-injection gwt-gin gwt-activities


    【解决方案1】:

    最适合我们的是使用辅助注射。

    根据情况,我们在活动本身、包中(用于构建该包中的所有活动)或 ActivityMapper 中定义活动工厂。

    public class MyActivity extends AbstractActivity {
       private final MyView view;
    
       @Inject
       MyActivity(MyView view, @Assisted MyPlace place) {
          this.view = view;
          ...
       }
       ...
    }
    
    public class MyActivityMapper implements ActivityMapper {
       public interface Factory {
         MyActivity my(MyPlace place);
    
         FooActivity foo(FooPlace place);
    
         ...
       }
    
       // using field injection here, feel free to replace by constructor injection
       @Inject
       private Factory factory;
    
       @Overrides
       public Activity getActivity(Place place) {
          if (place instance MyPlace) {
             return factory.my((MyPlace) place);
          } else if (place instance FooPlace) {
             return factory.foo((FooPlace) place);
          }
          ...
       }
    }
    
    // in the GinModule:
    install(new GinFactoryModuleBuilder().build(MyActivityMapper.Factory.class));
    

    顺便说一句,要使方法注入起作用,您仍然必须通过 GIN 创建活动,因此您会遇到与构造函数注入相同的问题。没有魔法,GIN 不会神奇地注入它不知道甚至不知道它们何时被实例化的类。您可以通过向 Ginjector 添加方法来显式触发方法注入,但我不建议这样做(您的代码将取决于 Ginjector,如果可以的话,您应该避免这样做):

    interface MyGinjector extends Ginjector {
       // This will construct a Foo instance and inject its constructors, fields and methods
       Foo foo();
    
       // This will inject methods and (non-final) fields of an existing Bar instance
       void whatever(Bar bar);
    }
    
    ...
    
    Bar bar = new Bar("some", "arguments");
    myGinjector.whatever(bar);
    ...
    

    最后一句话:我不会将 place 对象直接传递给活动。尝试解耦地点和活动,这允许您移动事物(例如,构建移动或平板电脑版本,您可以在主视图和详细视图之间切换,而不是并排显示它们)只需更改“外壳”布局和您的活动映射器。要真正解耦它们,您必须构建某种类型的 navigator,它会抽象您的 placeController.goTo() 调用,以便您的活动永远不会处理地点。

    【讨论】:

    • 嗨,Thomas,这正是我们在我们的应用程序中所做的(使用工厂)并且效果很好。但是,您如何建议将其与 GIN 的 AsyncProvider 集成以进行代码拆分? (我们正在使用 ActivityAsyncProxy ars-codia.raphaelbauer.com/2011/04/…
    【解决方案2】:

    我选择了一种稍微不同的方法,它具有您需要的所有灵活性。我不记得我在哪里选择了这个设计模式,但这不是我的主意。我这样创建活动

    public class MyActivity extends AbstractActivity{
    
        private MyView view;
        @Inject static PlaceController pc;
    
    
        @Inject
        public MyActivity(MyView view) {
            super();
            this.view = view;
        }
    
        public MyActivity withPlace(MyPlace myPlace) {
            return this;
        }
    ...
    }
    

    然后我像这样在活动映射器中使用它:

    public class MyMapper implements ActivityMapper {
    
        @Inject Provider<MyActivity> myActivityProvider;
    
        public Activity getActivity(Place place) {
    
            if ( place instanceof MyPlace){
                return myActivityProvider.get().withPlace(place);
            } else if
    ...
    

    还要确保视图在 gin 模块文件中声明为单例。

    【讨论】:

      【解决方案3】:

      根据我的经验,一个好的做法是使用单独的活动映射器来处理地点和活动(映射)。在您有演示者的活动中,这是一个活动的示例:

      public class ActivityOne extends AbstractActivity {
      
        @Inject
        private Presenter presenter;
      
        @Override
        public void start(AcceptsOneWidget panel, EventBus eventBus) {
          presenter.go(panel);
        }
      
      }
      

      presenter 内部注入了视图,它是在调用“go”方法时构造的(presenter)。演示者在GIN 模块中被声明为单例,并且视图通常是单例(除了一些例外,例如出现在许多地方的小部件)。

      这个想法是在演示者内部移动带有视图的联系人(因为演示者的目标是处理逻辑并从视图中检索/更新数据,根据MVP)。 在演示者内部,您还将拥有RPC 服务,您不必声明它们,因为GIN 将通过调用GWT.create“神奇地”为您创建实例 这是一个简单的演示者的示例:

          public class PresenterOneImpl implements Presenter {
      
            @Inject
            private MyView view;
      
      
            @Inject
            private SomeRpcServiceAsync someRpc;
      
      
            @Override
            public void go(AcceptsOneWidget panel) {
              view.setPresenter(this);
              panel.setWidget(view);
              updateTheViewWithData();
            }
      }
      

      最后我必须指出,有一些活动,例如菜单的活动,它直接处理地点和视图以显示当前状态。这些活动被缓存在映射器中,以避免每次更改位置时都出现新实例。

      【讨论】:

        猜你喜欢
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-23
        • 1970-01-01
        • 1970-01-01
        • 2011-11-29
        • 2012-03-13
        相关资源
        最近更新 更多