GWT中的Places/Activities和MVP的解释是什么?

5

我了解Places & Activities与MVP是分开的,P&A用于管理浏览器历史记录,而MVP是一种架构模式。但是,显然它们在某些领域中相互交织和重叠,这个问题是关于如何使它们协同工作,保持统一。

我刚刚了解了GWT Places & Activites和推荐的MVP结构,我的头有点晕。我需要有人确认我是否掌握了基本思想。

PlaceHistoryHandler具有PlaceControllerPlaceHistoryMapper。当您在浏览器地址栏中输入特定URL时,PlaceHistoryHandler使用其PlaceHistoryMapper确定应将哪个Place传递给其PlaceController。然后,PlaceController会将适当的PlaceChangeEvent发送到EventBus

一个或多个ActivityManager正在监听这些PlaceChangeEvent,并将这些Place映射到一个Activity,该Activity应该是MVP架构中的Presenter组件。

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

如果我说错了什么,误导了或者理解错了,请纠正我。基于这种理解即将编写大量代码...

3个回答

2
你有一个错误:你使用AcceptsOneWidgetActivityMapper(以及全局的EventBus)初始化了ActivityManagerActivityManager 监听PlaceChangeEvent,并向其ActivityMapper请求相应的Activity,然后start()它,传递它被初始化的AcceptsOneWidget和包装全局EventBusResetableEventBusAcceptsOneWidget是页面上将接收活动视图的插槽。当活动启动时,它会将其视图(作为IsWidget;提示:Widget本身实现了IsWidget)传递给AcceptsOneWidget,这就是它发出“这是要显示的内容,并立即显示”的信号。请注意,它可以同步地(从start()内部)或异步地(例如,从响应start()触发的RPC中)执行此操作。
关于MVP,许多人将Activity用作presenter,但这只是MVP的一种方式:
  • 有些人仅将活动用作其他组件(例如小部件)的生命周期管理器,这些组件本身使用MVP(或不使用)。因此,活动可以创建一个 presenter 和 view(或选择长寿命的任何一个实例;再次强调,presenter 通常是短寿命的,而视图 - 更难构建 - 是长寿命的,例如单例)并将它们初始化/重置为正确的状态;或者它只能创建/重用一个小部件并将其初始化/重置。
  • 有些人在小部件内部使用MVP作为实现细节。 CellTable (实际上几乎所有基于单元格的小部件)就是这样一个例子:它足够复杂,以至于 presenter 具有实际价值,但该 presenter 在API中根本未公开。您可以将此方法与上述方法混合使用:活动创建/重用小部件并将其初始化/重置,该小部件在内部使用MVP。
如果您想了解有关位置和活动的更多信息,请阅读我的博客文章:

当然,这还要加上官方文档


2
也许这可以帮助你一点点。
当我感到困惑时,我使用了这个图表模式: enter image description here

2
听起来你对这些概念有了相当不错的掌握。我已经用过几次Activities/Places API,但我仍然觉得有点困惑。以下是另一个关于组件的概述:
PlaceController - 你使用它告诉ActivityManager下一步要过渡到哪里,使用goTo方法。
ActivityManager - 管理运行的活动。调用start、stop、show等方法。
ActivityMapper - 把它看作一个工厂。根据给定的地点,它知道要创建哪个Activity。这通常是我注入RPC服务的地方。
Place - 将其视为应用程序中特定视图的“地址”。PlaceTokenizer通常在此处指定,但这更像是方便之举。
PlaceHistoryMapper - 这是将url令牌并使用您指定的PlaceTokenizers创建一个Place的类。
Activity - 活动代码应该能够接受一个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 Activities Places 的设置在这里: https://github.com/aglassman/jgoo/blob/master/JGoo/src/com/jgoo/client/CrudLauncher.java 这是测试应用程序的演示,您可以看到我使用PlaceTokenizers的不同方式来获取不同的视图。(请注意,数据存储有时需要几秒钟才能初始化,因此如果你点击“Get All”,它可能需要一段时间才能加载(没有加载旋转器,但它正在工作中)。如果你点击结果文本,它会带你到对象的视图。

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

希望这有所帮助!更新:添加了活动示例,说明它如何与MVP相关。在下面的示例中,PlaceTokenizer提供了一个活动类型,如果请求编辑,则提供UUID以映射到特定联系人。我使用Activity作为高级Presenter,几乎只是为了向较低级别的Presenter提供初始数据和信息,以便它能够完成工作。在较低级别的Presenter中,在本例中为RequestEditWidget和ContactInfoWidget,我使用UIBinder创建视图。请注意,我目前没有一种方法让Activity使用mayStop/onStop方法,但这只是需要一些额外代码来与我的小部件进行接口交互的问题。这些(编辑、订阅、请求编辑)中的每一个都可以成为自己的Activity,但我希望它们都具有相同的place前缀。
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());
                    }
                });
    }

}

谢谢@aglassman (+1) - 但是关于MVP方面的问题呢?如果你把具体的“Activity”视为一个Presenter,那么它需要一个View和一个Model来注入View。这个View应该是什么?一个“AcceptsOneWidget”?一个“Composite”?一个“HasWidget”?什么时候需要将其附加到根面板上?再次感谢! - user1768830
此外,您需要将Activities/Places管理的面板附加到ActivityManager。通常情况下,您可以在OnModuleLoad方法中完成此操作。 - aglassman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接