Joe, In fact, no it does not work properly with multiple instances, and this is a problem I discovered shortly after originally posting this. The solution I devised was to make the Proxy abstract and simply create concrete sub-classes for each Presenter I want to proxy (anonymous sub-classes do not work!). This is a little tedious, but the abstraction I wrote makes it pretty simple to implement. Below is the updated code. Note that I also changed the ViewProxy to use a LayoutPanel instead of a SimplePanel so that proxied views that implement RequiresLayout are supported.
/** * PresenterProxy wraps a Presenter implementation and acts as a gateway to that * Presenter. The wrapped Presenter is created on-demand the first time any * method is called, or optionally it can be created eagerly at the time the * PresenterProxy is created. * * Instantiation of the wrapped Presenter occurs behind a GWT.runAsync() call so * that complex wrapped Presenters may be split out into code fragments during * module compilation. * * In order to achieve this "delayed" instantiation, the PresenterProxy must be * given a Provider<T extends Presenter> instance to provide the actual * implementation at the appropriate time. * * Additionally, a ViewProxy is utilized that consists of a LayoutPanel to * minimize the impact on the UI. The ViewProxy can be inserted into the DOM * immediately without waiting for the wrapped Presenter to become available. * * Any calls made to the wrapped Presenter before the instance becomes available * are queued in a buffer and later replayed when the instance becomes * available. Once available, all calls are executed immediately on the wrapped * instance. * * @author jcarlson * * @param <T> */ public abstract class PresenterProxy<T extends Presenter> implements Presenter { private static class ProxyView implements View { LayoutPanel proxy = new LayoutPanel(); ProxyView() { } @Override public Widget asWidget() { return this.proxy; } protected void setView(View view) { this.proxy.clear(); this.proxy.add(view.asWidget()); } } private boolean asyncCalled; private boolean bound; private HandlerManager bus; private T impl; private Queue<Command> queue; private ProxyView view; public PresenterProxy(HandlerManager bus) { this(bus, false); } public PresenterProxy(HandlerManager bus, boolean eager) { this.bus = bus; this.queue = new LinkedList<Command>(); this.view = new ProxyView(); if (eager) { ensurePresenter(); } } @Override public final void bind() { this.bound = true; queue(new Command() { @Override public void execute() { PresenterProxy.this.impl.bind(); } }); } @Override public final View getView() { return this.view; } @Override public final void handleHistory(final HistoryItem item) { queue(new Command() { @Override public void execute() { PresenterProxy.this.impl.handleHistory(item); } }); } @Override public final boolean isBound() { return this.bound; } @Override public final void release() { queue(new Command() { @Override public void execute() { PresenterProxy.this.impl.release(); } }); this.bound = false; } protected final void onAsyncFailure(Throwable reason) { PresenterProxy.this.bus .fireEvent(new ApplicationExceptionEvent(reason)); } protected final void onAsyncSuccess(T impl) { // set impl instance this.impl = impl; // fill-in proxy view this.view.setView(PresenterProxy.this.impl.getView()); // execute any queued commands while (ResizingPresenterProxy.this.queue.peek() != null) { Command cmd = PresenterProxy.this.queue.poll(); cmd.execute(); } } /** * The key method that subclasses must override. * This allows each GWT.runAsync() call to be in its own * concrete class, thus allowing the compiler to produce * multiple exclusive fragments. */ protected abstract void runAsync(); void ensurePresenter() { if (!this.asyncCalled) { this.asyncCalled = true; runAsync(); } } void queue(Command command) { ensurePresenter(); if (this.impl != null) { command.execute(); } else { this.queue.offer(command); } } } And an implementation of the proxy: public class MyPresenterProxy extends PresenterProxy<ProfilePresenter> { private Provider<ProfilePresenter> provider; @Inject public MyPresenterProxy(HandlerManager bus, Provider<ProfilePresenter> provider) { super(bus); this.provider = provider; } @Override protected void runAsync() { GWT.runAsync(new RunAsyncCallback() { @Override public void onFailure(Throwable reason) { onAsyncFailure(reason); } @Override public void onSuccess() { MyPresenter presenter = MyPresenterProxy.this.provider .get(); onAsyncSuccess(presenter); } }); } } On Feb 8, 3:31 am, Joe Cheng <j...@joecheng.com> wrote: > Jarrod, are you using this ProxyPresenter more than once within the same > application (with different presenter type parameters), and found that it > introduced the split points as expected? I originally tried something like > this but found that it would only ever introduce a single split point, no > matter how many times I used it. > > I was able to solve the problem using deferred binding and was about to > write a blog post about it, but if your code actually works as desired then > I need to go back and figure out what I was doing wrong. > > > > On Mon, Jan 25, 2010 at 8:16 PM, jarrod <jarrod.carl...@gmail.com> wrote: > > While building an application for my company, I needed a way to make > > large sections of the application sit behind a split point. After > > organizing my application into "modules" of related functionality, I > > came up with slick, easy way to make those "modules" split out > > automatically: by using a proxy presenter. > > > My application uses gin and a hand-made MVP framework based loosely > > off of gwt-presenter. Some adaptation may be necessary to fit your > > particular frameworks, but here goes: > > > public class ProxyPresenter<T extends Presenter> implements Presenter > > { > > > private static class ProxyView implements View { > > > SimplePanel proxy = new SimplePanel(); > > > ProxyView() { > > > } > > > �...@override > > public Widget asWidget() { > > return this.proxy; > > } > > > protected void setView(View view) { > > this.proxy.setWidget(view.asWidget()); > > } > > > } > > > private boolean asyncCalled; > > private boolean bound; > > > private HandlerManager bus; > > private T impl; > > private Provider<T> provider; > > private Queue<Command> queue; > > private ProxyView view; > > > public ProxyPresenter(HandlerManager bus, Provider<T> provider) { > > this(bus, provider, false); > > } > > > public ProxyPresenter(HandlerManager bus, Provider<T> provider, > > boolean eager) { > > this.bus = bus; > > this.provider = provider; > > this.queue = new LinkedList<Command>(); > > this.view = new ProxyView(); > > if (eager) { > > ensurePresenter(); > > } > > } > > > �...@override > > public void bind() { > > this.bound = true; > > queue(new Command() { > > > �...@override > > public void execute() { > > ProxyPresenter.this.impl.bind(); > > } > > > }); > > } > > > �...@override > > public View getView() { > > return this.view; > > } > > > �...@override > > public void handleHistory(final HistoryItem item) { > > queue(new Command() { > > > �...@override > > public void execute() { > > ProxyPresenter.this.impl.handleHistory(item); > > } > > > }); > > } > > > �...@override > > public boolean isBound() { > > return this.bound; > > } > > > �...@override > > public void release() { > > queue(new Command() { > > > �...@override > > public void execute() { > > ProxyPresenter.this.impl.release(); > > } > > }); > > this.bound = false; > > } > > > protected void ensurePresenter() { > > if (!this.asyncCalled) { > > this.asyncCalled = true; > > GWT.runAsync(new RunAsyncCallback() { > > > �...@override > > public void onFailure(Throwable reason) { > > ProxyPresenter.this.bus > > .fireEvent(new ApplicationExceptionEvent > > (reason)); > > } > > > �...@override > > public void onSuccess() { > > > // get impl instance > > ProxyPresenter.this.impl = > > ProxyPresenter.this.provider > > .get(); > > > // fill-in proxy view > > ProxyPresenter.this.view.setView > > (ProxyPresenter.this.impl > > .getView()); > > > // execute any queued commands > > while (ProxyPresenter.this.queue.peek() != null) { > > Command cmd = ProxyPresenter.this.queue.poll > > (); > > cmd.execute(); > > } > > > } > > }); > > } > > } > > > protected void queue(Command command) { > > ensurePresenter(); > > if (this.impl != null) { > > command.execute(); > > } else { > > this.queue.offer(command); > > } > > } > > > T getPresenter() { > > return this.impl; > > } > > > } > > > Then, in my gin module, instead of using an explicit bind, I use a > > @Provides method, like so: > > > �...@provides > > Presenter getRealPresenter(HandlerManager bus, > > Provider<RealPresenter> provider) { > > return new ProxyPresenter<RealPresenter>(bus, provider); > > } > > > The rest is automagic! > > > -- > > You received this message because you are subscribed to the Google Groups > > "Google Web Toolkit" group. > > To post to this group, send email to google-web-tool...@googlegroups.com. > > To unsubscribe from this group, send email to > > google-web-toolkit+unsubscr...@googlegroups.com<google-web-toolkit%2Bunsubs > > cr...@googlegroups.com> > > . > > 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 google-web-tool...@googlegroups.com. To unsubscribe from this group, send email to google-web-toolkit+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.