解释GWT场所/活动& MVP?

时间:2013-06-25 16:24:03

标签: java gwt mvp gwt-places gwt-activities

我明白地方&活动与MVP分开。 P& A用于管理浏览器历史记录,MVP是一种架构模式。但是,显然,它们在区域中交错和重叠,而这个问题是关于它们如何能够团结一致地协同工作。

我刚读了GWT Places&活动,推荐的MVP结构,我的脑袋在旋转。我需要有人确认我有基本的想法。

PlaceHistoryHandler同时包含PlaceControllerPlaceHistoryMapper。当您在浏览器地址栏中输入特定网址时,PlaceHistoryHandler会使用其PlaceHistoryMapper来确定应将哪个Place传递给其PlaceController。反过来,PlaceController会在PlaceChangeEvent上触发相应的EventBus

一个或多个ActivityManager正在公共汽车上搜索此类PlaceChangeEvent s,并将这些Place映射到Activity,这应该是<{1}} MVP架构中的strong> Presenter 组件。

返回的具体Activity(演示者)应该具有实现AcceptsOneWidget的模型注入视图(通常是UiBinder)。然后启动此AcceptsOneWidget组件(通过Activity#start(...)),GWT - 自动 - 将其内容呈现给浏览器。

我所说的是不正确,误导或误解的?如果是这样,请纠正我。基于这种理解,很多代码即将被编写......

3 个答案:

答案 0 :(得分:2)

听起来你对这些概念有了相当不错的把握。我曾经使用过Activities / Places API几次,但我仍然觉得它有点令人困惑。以下是关于如何考虑组件的另一个概述:

PlaceController - 用于告诉ActivityManager使用goTo转换到next的位置。

ActivityManager - 管理正在运行的活动。通话开始,停止,显示等。

ActivityMapper - 将其视为工厂。它知道基于给定位置创建的Activity。这是我通常注入RPC服务的地方。

地点 - 将此视为应用程序中特定视图的“地址”。 PlaceTokenizer通常在这里指定,但这更方便。

PlaceHistoryMapper - 这是将使用url标记的类,并使用您指定的PlaceTokenizers创建一个Place ../ / p>

活动 - 活动代码应该能够获取Place对象,并将您的应用程序带到该位置。如果两个Place对象相同,则每次都应显示相同的内容。

这是我编写的使用Activities Places的测试应用程序的一个(可能不是很棒)示例。我有两个使用此应用程序的应用程序: https://github.com/aglassman/jgoo/tree/master/JGoo/src/com/jgoo/client/appnav https://github.com/aglassman/jgoo/tree/master/JGoo/src/com/jgoo/client/crud/nav

活动地点在此处设置: https://github.com/aglassman/jgoo/blob/master/JGoo/src/com/jgoo/client/CrudLauncher.java

以下是测试应用的实际应用,您可以看到我使用PlaceTokenizers获取不同视图的不同方式。 (注意,数据存储区有时需要几秒钟来初始化,所以如果你“全部获取”,可能需要一段时间才能加载(没有加载微调器,但它正在工作)。如果你点击结果文本,它会带你到对象的观点。

http://jgoo-sample.appspot.com/

希望这有帮助!

更新:添加了活动示例,它如何与MVP联系

在下面的示例中,PlaceTokenizer提供了一种活动类型,如果请求编辑,则会提供UUID以映射到特定联系人。我将Activity用作高级演示者,几乎只是为较低级别的演示者提供了完成其工作所需的信息中的初始数据。在较低级别的演示者(在本例中为RequestEditWidget)和ContactInfoWidget中,我使用UIBinder创建视图。请注意,我目前没有办法让活动使用mayStop / onStop方法,但这只是与我的小部件交互的一些额外代码。

其中每一个(编辑,订阅,request_edit)都可能都在他们自己的活动中,但我希望他们都拥有相同的地方前缀。

package contactmanager.client.nav;

import contactmanager.client.ContactManagerServiceAsync;
import contactmanager.client.callback.BasicCallback;
import contactmanager.client.contact.info.ContactInfoWidget;
import contactmanager.client.contact.info.RequestEditWidget;
import contactmanager.shared.bundle.InitDataBundle;
import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

public class ContactActivity extends AbstractActivity{

    public enum Activity {
        request_edit,
        edit,
        subscribe
    }

    private ContactManagerServiceAsync cmsa;
    private ContactPlace place;
    private PlaceController pc;

    public ContactActivity(PlaceController pc, ContactManagerServiceAsync cmsa,ContactPlace place)
    {
        this.pc = pc;
        this.cmsa = cmsa;
        this.place = place;
    }

    public void start(AcceptsOneWidget panel, EventBus eventBus) {
        switch(place.activity)
        {
            case request_edit:
                loadRequestEditPanel(panel);
                break;

            case edit:
                loadEditPanel(panel);
                break;

            case subscribe:
                loadSubscribePanel(panel);
                break;
        }
    }

    private void loadSubscribePanel(final AcceptsOneWidget panel) {
        cmsa.getInitDataBundle(new BasicCallback<InitDataBundle>() {
            @Override
            public void onSuccess(InitDataBundle result) {
                panel.setWidget(new ContactInfoWidget(pc,cmsa,result,null).getWidget());
            }   
        });
    }

    private void loadRequestEditPanel(final AcceptsOneWidget panel) {
        panel.setWidget(new RequestEditWidget(pc,cmsa).getWidget());
    }

    private void loadEditPanel(final AcceptsOneWidget panel) {
        cmsa.getInitDataBundle(new BasicCallback<InitDataBundle>() {

                    public void onSuccess(InitDataBundle result) {
                        panel.setWidget(new ContactInfoWidget(pc,cmsa,result,place.uuid).getWidget());
                    }
                });
    }

}

答案 1 :(得分:2)

您有一个错误:您使用ActivityManagerAcceptsOneWidget(以及全局ActivityMapper)初始化EventBusActivityManager收听PlaceChangeEvent并向其ActivityMapper询问相应的Activitystart(),并通过AcceptsOneWidget初始化,以及包裹全局ResetableEventBus的{​​{1}} EventBus是页面上的广告位,它将接收活动的视图。当活动开始时,它会将其视图(作为AcceptsOneWidget;提示:IsWidget实现Widget本身)传递给IsWidget,这就是它如何发出信号“这是什么展示,现在展示“。请注意,它可以同步(从AcceptsOneWidget内)或异步(例如,从start()触发的RPC的响应中执行此操作。

关于MVP,很多人使用start()作为演示者,但这只是做MVP的一种方式:

  • 有些人将活动仅用作生命周期管理器,用于自己使用MVP(或不使用)的其他组件(例如小部件)。因此,一个活动可以创建一个演示者和视图(或者选择其中任何一个的长期实例;同样,一般来说,演示者是短暂的,而视图 - 更重要的构建 - 是一个长期存在的,例如单身)并初始化/将它们重置为正确的状态;或者它可以只创建/重用一个小部件并初始化/重置它。
  • 一些人在小部件中使用MVP作为实现细节。 Activity(实际上几乎所有基于单元格的小部件)就是这样一个例子:它足够复杂,以至于演示者具有真实价值,但该演示者根本没有在API中公开。您可以将此方法与上述方法混合使用:活动创建/重用小部件并初始化/重置它,并且该小部件在内部使用MVP。

如果您想了解更多有关地点和活动的信息,我建议您阅读我的博文:

这当然是official documentation

的补充

答案 2 :(得分:2)

也许这可以帮助你一点点

当我感到困惑时,我使用了这个模式:

enter image description here