Ah, well I'd be interested to see what you come up with as far as reducing the boilerplate.
I had tried a few different scenarios, but I found that unless the actual call to GWT.runAsync for each proxied Presenter was in a unique class then the compiler wouldn't split out the code properly. I'm guessing the code-splitting mechanism in the compiler pivots at least in part on the class containing the call. On Feb 9, 4:14 pm, Joe Cheng <[email protected]> wrote: > OK, great, I went through a similar approach previously. The new approach > I'm using is similar but you can remove the boilerplate in the proxy > implementation, as the deferred binding mechanism will fill it all in. In > fact since you're using Gin it will literally look like this: > > public abstract class MyAsyncShim extends AsyncShim<MyPresenter> { } > > I'll reply to this thread when I have something written up. I would also > like to adapt your idea of using a command queue, right now I'm doing > something similar but not guaranteeing the methods will be executed in the > order they were invoked. > > > > On Tue, Feb 9, 2010 at 8:42 AM, jarrod <[email protected]> wrote: > > 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 <[email protected]> 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 <[email protected]> > > 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... > > read more » -- 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.
