调用异步函数时自动“加载”指示符

我正在寻找一种方法来在调用异步服务时自动显示和隐藏“加载”消息,所以不要这样做:

showLoadingWidget(); service.getShapes(dbName, new AsyncCallback() { public void onSuccess(Shape[] result) { hideLoadingWidget(); // more here... } public void onFailure(Throwable caught) { hideLoadingWidget(); //more here } }); 

我想这样做,但仍然在完成时显示和隐藏消息。

 // this should be gone: showLoadingWidget(); service.getShapes(dbName, new AsyncCallback() { public void onSuccess(Shape[] result) { // this should be gone: hideLoadingWidget(); // more here... } public void onFailure(Throwable caught) { //this should be gone: hideLoadingWidget(); //more here } }); 

总之,我想改变异步调用的行为。 感谢您提出所有可能的建议。

丹尼尔

您可以将调用本身包装在处理显示加载消息的对象中,可能会在错误或其他情况下重试几次。 像这样的东西:

 public abstract class AsyncCall implements AsyncCallback { /** Call the service method using cb as the callback. */ protected abstract void callService(AsyncCallback cb); public void go(int retryCount) { showLoadingMessage(); execute(retryCount); } private void execute(final int retriesLeft) { callService(new AsyncCallback() { public void onFailure(Throwable t) { GWT.log(t.toString(), t); if (retriesLeft <= 0) { hideLoadingMessage(); AsyncCall.this.onFailure(t); } else { execute(retriesLeft - 1); } } public void onSuccess(T result) { hideLoadingMessage(); AsyncCall.this.onSuccess(result); } }); } public void onFailure(Throwable t) { // standard error handling } ... } 

要拨打电话,请执行以下操作:

 new AsyncCall() { protected void callService(AsyncCallback cb) { DemoService.App.get().someService("bla", cb); } public void onSuccess(DTO result) { // do something with result } }.go(3); // 3 retries 

您可以使用代码扩展它以检测需要很长时间的呼叫并显示某种繁忙的指示符等。

以下AsyncCall是我目前正在使用的(受David Tinker解决方案的启发)。 而不是重试,这需要一些RPC调用需要很长时间才能返回,并且如果在指定的超时之前没有返回调用,则显示加载指示符。

AsyncCall还会跟踪当前正在进行的RPC调用的数量,并且只有在返回所有RPC调用时才隐藏加载指示符。 使用David的解决方案,加载指示器可能会被早期的RPC调用隐藏,即使另一个仍在进行中。 这个if课程假设加载指示器小部件是应用程序的全局,这在我的情况下。

 public abstract class AsyncCall { private static final int LOADING_TOLERANCE_MS = 100; private static int loadingIndicatorCount = 0; private Timer timer; private boolean incremented; private boolean displayFailure; public AsyncCall(boolean displayFailure) { this.displayFailure = displayFailure; timer = new Timer() { @Override public void run() { if (loadingIndicator++ == 0) // show global loading widget here incremented = true; } }; timer.schedule(LOADING_TOLERANCE_MS); call(new AsyncCallback() { @Override public void onSuccess(T result) { timer.cancel(); if (incremented && --loadingIndicatorCount == 0) // hide global loading widget here callback(result); } @Override public void onFailure(Throwable caught) { timer.cancel(); if (incremented && --loadingIndicatorCount == 0) // hide global loading widget here if (AsyncCall.this.displayFailure) // show error to user here } }); protected abstract void call(AsyncCallback cb); protected void callback(T result) { // might just be a void result or a result we // wish to ignore, so do not force implementation // by declaring as abstract } } 

完整的例子(罗伯特)

 public abstract class AsyncCall implements AsyncCallback { public AsyncCall() { loadingMessage.show(); } public final void onFailure(Throwable caught) { loadingMessage.hide(); onCustomFailure(caught); } public final void onSuccess(T result) { hideLoadingMessage(); onCustomSuccess(result); } /** the failure method needed to be overwritte */ protected abstract void onCustomFailure(Throwable caught); /** overwritte to do something with result */ protected abstract void onCustomSuccess(T result); } 

您可以创建一个默认的回调超类,它在其构造函数中接受一个LoadingMessage对象参数,并为子类提供钩子方法,例如onSuccess0onFailure0

实施类似于:

 public final void onFailure(Throwable caught) { loadingMessage.hide(); onFailure0(caught); } protected abstract void onFailure0(Throwable caught); 

这是我的版本,与上面的版本非常相似,但有一些差异

 public abstract class LoadingAsyncCallback implements AsyncCallback { /** * Override this method and call the async service method providing the arguments needed. * @param args */ public abstract void callService(Object... args); /** * Call execute() to actually run the code in overriden method callService() * @param args: arguments needed for callService() method */ public void execute(Object... args) { //your code here to show the loading widget callService(args); } @Override public void onFailure(Throwable caught) { //your code here to hide the loading widget onCallbackFailure(caught); } @Override public void onSuccess(T result) { //your code here to hide the loading widget onCallbackSuccess(result); } public abstract void onCallbackFailure(Throwable caught); public abstract void onCallbackSuccess(T result); } 

一个简单的例子如下:

 MyServiceAsync myServiceAsync = GWT.create(MyService.class); LoadingAsyncCallback loadingAsyncCallback = new LoadingAsyncCallback() { @Override public void callService(Object... args) { myServiceAsync.someMethod((String) args[0], (String) args[1], this); } @Override public void onCallbackFailure(Throwable caught) { } @Override public void onCallbackSuccess(Object result) { } }; String name = "foo"; String login = "bar"; loadingAsyncCallback.execute(name, login ); 

如果有人在RPC调用期间寻找将屏幕元素 (小部件/组件) 标记 为忙的方法 ,我实现了一个小实用程序 。

它禁用组件并插入具有特定样式的“div”。 当然,这一切都可以解除。

在撰写本文时,这是应用于div的样式:

 @sprite .busySpinner { gwt-image: "spinnerGif"; background-repeat: no-repeat; background-position: center; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10000; /* Something really high */ } 

实用方法:

 /** * Disables the given component and places spinner gif over top. */ public static void markBusy(final Component c) { c.disable(); ensureNotBusy(c); // NOTE: Don't add style to the component as we don't want 'spinner' to be disabled. c.getElement().insertFirst("
"); } /** * Enables the given component and removes the spinner (if any). */ public static void clearBusy(Component c) { c.enable(); if (!ensureNotBusy(c)) { GWT.log("No busy spinner to remove"); } } private static boolean ensureNotBusy(Component c) { Element first = c.getElement().getFirstChildElement(); if (first != null && first.removeClassName(STYLE.busySpinner())) { first.removeFromParent(); return true; } return false; }