MVP best practices, how to expose a view to a presenter?

269 views
Skip to first unread message

Alex D.

unread,
Jul 2, 2011, 7:25:11 AM7/2/11
to google-we...@googlegroups.com
Hi guys,

I've been trying to find the best answer to the question above for a while now. Here is the problem:

* assume you have a view with textbox and a vertical panel. The textbox is used for searching, the vertical panel to display the found results. 
In order to decouple everything, we'll define 2 interfaces:

interface ISearchView {
  void populateResults (List<String> results);
  setPresenter (ISearchPresenter p);
}

interface ISearchPresenter {
  void doSearch (String query);
}

* using the code above, I can safely bind events in view, that dispatch business execution to a presenter (set via #setPresenter). Everything is very clean & organized.

However, when I'm implementing an Activity, here is how it would look like:

class SearchActivity extends AbstractActivity implements ISearchPresenter {

@Override
public void start(final AcceptsOneWidget panel, EventBus eventBus) {
           ISearchView view = clientFactory.getSearchView();
           view.setPresenter (this);
           panel.setWidget (view);
        }

        @Override
        public void onSearch (String query) {
             // Execute some sync/async call.
             clientFactory.searchService().search (query, .......);

             // HOW DO I SEND RESULTS BACK TO VIEW??
        }
}


I don't know how to access the view instance, in order to populate it with some results. One way, which I honestly think it's uberly wrong -- is to access it through clientFactory.getSearchView. But this basically forces me to have a singleton scope of that view. Not acceptable, imo.

The example http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html doesn't include this case (by coincidence or ...)

Thanks.

Thomas Broyer

unread,
Jul 2, 2011, 9:22:48 AM7/2/11
to google-we...@googlegroups.com
Keep a reference on the view in a field; and if you want to make sure you won't use the view after the activity is stopped, reset the field back to null in onCancel and onStop.

What I generally do is to inject/pass the view in the activity's constructor and store it in a field; and only setPresenter from the start method (like you did), and setPresenter(null) from onStop and onCancel (to make sure the view doesn't keep a reference on the activity once that one is stopped). That way, I can easily decide the lifetime of the view: singleton, "cached for a while", or created each time a new activity is needed. By injecting in the activity's constructor though, I assume that the activity's lifetime is shorter than the one of the view (my activities are all disposable: once they're stopped or cancelled, it's an error to try to start them again, my code should create a new activity), YMMV.

Alex D.

unread,
Jul 2, 2011, 2:56:16 PM7/2/11
to google-we...@googlegroups.com
That sounds right :).
Message has been deleted

Juan Pablo Gardella

unread,
Jul 22, 2011, 10:59:18 AM7/22/11
to google-we...@googlegroups.com
I define an interface in the presenter as mention in http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html

2011/7/22 Karthik Reddy <karthik...@gmail.com>
@Thomas

When you say  "cached for a while"  could you give an example how this can be achieved. (For example: Do you maintain the time it needs to be cached for, in a separate variable.  )

In concept, I am able to understand but the execution details are kinda teasing my mind.....

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/-FQBR0HgrTEJ.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Thomas Broyer

unread,
Jul 22, 2011, 11:39:26 AM7/22/11
to google-we...@googlegroups.com
If you use dependency injection properly, then it'd be done at the moment you "getXxxView" from your "client factory" (to use the terms from the GWT articles re. MVP).
Instead of:
private XxxView xxxView; // singleton
public XxxView getXxxView() {
   if (xxxView == null) {
      xxxView = new XxxView(...dependencies here...);
   }
   return xxxView;
}
You'd have something like:
private XxxView xxxView; // cached for a while
private Timer resetXxxView = new Timer() {
   @Override
   public void run() {
      xxxView = null;
   }
};
public XxxView getXxxView() {
   if (xxxView == null) {
      xxxView = new XxxView(...dependencies here...);
   }
   resetXxxView.schedule(...sliding window...);
   return xxxView;
}

If you're using GIN, it's unfortunately a bit hard to do it... until GIN implements custom scopes.
(honestly, I never tried, I'm just using singletons for now)
Message has been deleted

Jens

unread,
Jul 22, 2011, 11:56:48 AM7/22/11
to google-we...@googlegroups.com
Couldn't you just implement a provider for a given view in the same way when using GIN?

In XxxViewProvider.get() you would do the same as in your getXxxView() method. Doesn't seem that hard but honestly I've never tried it and maybe I'm missing something.

-- J.

Thomas Broyer

unread,
Jul 25, 2011, 4:07:04 AM7/25/11
to google-we...@googlegroups.com
You'd have to either juggle with binding annotations (and possibly private modules), or have the same dependencies in your provider as in your provided class (to be able to 'new' the class yourself in the provider) and keep them in sync.
IMO, unless you're in a hurry, if this is absolutely necessary (i.e. you cannot live with either a singleton or the default behavior) then you'd better contribute the support for custom scopes to GIN.
Reply all
Reply to author
Forward
0 new messages