在GWT活动中使用GIN



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

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

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

  3. 在Activity的ctor中使用GWT.create构建注入器。没用,因为他们不会再单身了。

对我们最有效的是使用辅助注射。

根据具体情况,我们在活动本身、包(用于构建该包中的所有活动)或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不会神奇地注入它不知道的类,甚至不知道它们何时被实例化。您可以通过向Gijector中添加方法来显式触发方法注入,但我不建议这样做(您的代码将依赖于Gijector,如果可以的话,这是您应该避免的):

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对象直接传递给活动。尝试将地点和活动解耦,这样只需更改"外壳"布局和活动映射器,就可以四处移动(例如,构建移动或平板电脑版本,在主视图和详细视图之间切换,而不是并排显示)。要真正解耦它们,您必须构建某种导航器,它将抽象您的placeController.goTo()调用,这样您的活动就永远不会涉及位置。

我选择了一个略有不同的方法,它具有您所需的所有灵活性。我不记得我是从哪里学会这个设计模式的,但这不是我的主意。我将活动创建为这样的

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
...

还要确保View在gin模块文件中声明为singleton。

根据我的经验,一个好的做法是使用单独的活动映射器来处理位置和活动(映射)。在你有演讲者的活动中,这里有一个活动的例子:

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

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

其想法是在演示者内部移动带有视图的联系人(根据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();
      }
}

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

相关内容

  • 没有找到相关文章

最新更新