5

我了解地点和活动与 MVP 是分开的。P&A 用于管理浏览器历史,MVP 是一种架构模式。但是,很明显,它们在区域上交错和重叠,这个问题是关于它们如何能够团结一致地一起工作。

我刚刚阅读了 GWT Places & Activites,并推荐了 MVP 结构,我头晕目眩。我需要有人来确认我有基本的想法。

APlaceHistoryHandler同时具有 aPlaceControllerPlaceHistoryMapper。当您在浏览器地址栏中输入特定 URL 时,它会PlaceHistoryHandler使用它PlaceHistoryMapper来确定Place应该将哪个 URL 传递给它的PlaceController. 反过来PlaceController,将适当的发射PlaceChangeEventEventBus.

一个或多个ActivityManagers 在总线上侦听此类PlaceChangeEvents,并将这些 s 映射Place到一个Activity,这应该是 MVP 架构中的Presenter组件。

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

我所说的是否不正确、误导或误解?如果是这样,请纠正我。很多代码都是基于这个理解写的……

4

3 回答 3

2

你有一个问题:你用 an和 an (和 global )初始化ActivityManagers 。监听并询问其对应的,然后传递它,传递初始化它的 ,以及包装全局的 a 。 这是页面上的一个插槽,它将接收活动的视图。当活动开始时,它会将其视图(作为; 提示:实现自身)传递给,这就是它如何表示“这是要显示的内容,现在就显示”。请注意,它可以同步进行(从内部AcceptsOneWidgetActivityMapperEventBusActivityManagerPlaceChangeEventActivityMapperActivitystart()AcceptsOneWidgetResetableEventBusEventBus
AcceptsOneWidgetIsWidgetWidgetIsWidgetAcceptsOneWidgetstart()start()) 或异步的(例如,从对触发的 RPC 的响应)。

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

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

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

这当然是对官方文档的补充。

于 2013-06-26T13:09:23.043 回答
2

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

PlaceController - 你用来告诉 ActivityManager 下一步要转换到哪里,使用 goTo。

ActivityManager - 管理正在运行的活动。呼叫开始、停止、显示等。

ActivityMapper - 把它想象成一个工厂。它知道根据给定地点创建什么活动。这是我通常注入我的 RPC 服务的地方。

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

PlaceHistoryMapper - 这是将获取 url 令牌的类,并使用您指定的 PlaceTokenizers 创建一个 Place 出来。

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

这是我编写的使用活动场所的测试应用程序的一个(可能不是很好的)示例。我有两个使用此应用程序的部分: https ://github.com/aglassman/jgoo/tree/master/JGoo/src/com/jgoo/client/appnav https://github.com/aglassman/jgoo/树/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/

希望这可以帮助!

更新:添加了 Activity 示例,它如何与 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());
                    }
                });
    }

}
于 2013-06-25T18:54:22.587 回答
2

也许这可以帮助你一点

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

在此处输入图像描述

于 2013-06-30T17:55:03.017 回答