Very interresting Thomas. It is similar in some ways to the gwt-presenter project.
Just a question. You says that views are singleton. I understand the reason (efficiency). But does not it leads to UI state problems ? By instance, if you call a method on your view that adds a new css class to an element, it means that you will have to remove it before destroying the PresenterActivity (if you want to reuse it later). Or do you have a special mechanism to handle such cases ? Nicolas. 2010/11/4 Thomas Broyer <[email protected]> > > > On 4 nov, 03:32, David Chandler <[email protected]> wrote: > > Thanks for your thoughts, Nicolas. I believe the reason we've not > > created View and Presenter interfaces to date is because there are two > > different styles of MVP widely in use, only one of which allows the > > view to call the presenter as in your example. Which leaves us in the > > funny position that the new MVP framework is missing *formal* > > definitions of View and Presenter. Personally, I think it's a good > > thing that GWT Activities and Places are independent of views and > > presenters so as not to force you into one model. I think View and > > Presenter as you've described would fall in the category of things > > that are not quite core code, but are nevertheless useful abstractions > > that probably need a home in the GWT source somewhere for reference. > > We'll chew on this a bit for 2.1.1... > > FYI, we created in our project two abstract Activity classes: > - a SimplePresenterActivity: you must pass a view instance to the > constructor; the start method is final and calls an abstract doStart > method without passing the AcceptsOneWidget. Subclasses never see the > AcceptsOneWidget instance so they cannot mess with it, they just call > a reveal() method when they're ready to be displayed. In addition > there are isActive() and isDead() methods (isActive == true between > start and stop/cancel, whereas isDead only becomes true after stop/ > cancel, i.e. isDead is false between ctor and start). The view is > accessible through a getView() method, which is guarded by assertions > that the activity isActive(). What it means is that, when assertions > are enabled, subclasses cannot "touch" the view unless they're active > (because the view can be shared by several activity instances, so they > don't step on each other), and if tests are correctly done/written, > developers are forced to check that the activity still isActive() from > within their async callbacks. > - a PresenterActivity that extends SimplePresenterActivity and a) > enforce the fact the the view has a "delegate" (and a setDelegate > method) and b) automatically calls setDelegate when appropriate, with > the appropriate value; this is so that developers do not mistakenly > call view.setDelegate(this) from within the constructor. > > We do have "test helpers", to be used in the unit tests for the > subclasses, to test the scenarios where the activity is cancelled > (i.e. cancel the activity, then "simulate" an RF/RPC/RequestBuilder > response; it'll fail if it doesn't check isActive() before calling > reveal() or getView()) > > In brief, this "microframework" enforces that: > - activities are not reusable > - only one activity can "see" (and manipulate) the view at a time > (views are singletons) > The downside is that it makes extensive use of generics and declaring > a subclass of PresenterActivity look tricky if you don't know which > type parameter values to use. > > For instance, here's what a FooActivity could look like: > class FooActivity extends PresenterActivity<FooActivity, FooView> > implements FooView.Delegate { > private final MyRequestFactory requests; > > @Inject > FooActivity(FooView view, MyRequestFactory requests) { > super(view); > this.requests = requests; > } > > @Override > protected void doStart(EventBus eventBus) { > // example using RequestFactory > requests.getFooRequest().getAllFoos().fire(new > Receiver<List<Foo>>() { > public void onSuccess(List<Foo> foos) { > if (isActive()) { > getView().setFoos(foos); > reveal(); > } > } > }); > } > > ... > } > > @ImplementedBy(FooViewImpl.class) > interface FooView extends PresenterActivity.View<FooView.Delegate> { > > interface Delegate { ... } > > void setFoos(List<Foo> foos); > } > > class FooViewImpl extends Composite implements FooView { > private Delegate delegate; > > public void setDelegate(Delegate delegate) { > this.delegate = delegate; > } > > ... > } > (we do not currently have an abstract class for the views) > > For the background on these choices, see my comments on > http://gwt-code-reviews.appspot.com/925801/show > > Time will tell if it's a good approach. > > -- > You received this message because you are subscribed to the Google Groups > "Google Web Toolkit" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]<google-web-toolkit%[email protected]> > . > For more options, visit this group at > http://groups.google.com/group/google-web-toolkit?hl=en. > > -- You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
