GWT中的同步RPC调用

9

仅凭这个标题就可能会有人拿着棍子砸我,但请听我说。

我有一个使用案例,在异步调用后需要返回一个值。(我使用的是GWT-Platform,但概念相同。)我声明了一个最终的JavaScriptObject数组,然后在AsyncCallback内部分配了值。然而,我需要返回这个值,但方法在AsyncCallback完成之前就已经返回了。因此,我需要以某种方式进行阻塞,直到AsyncCallback完成。我需要在另一个方法中使用返回的值,或者在onSuccess()中做我需要的事情。

我尝试了循环、计时器和其他一些方法,但都没有成功。有人可以帮忙吗?

@Override
public JavaScriptObject doGetWhereAmIMarker(final double lng, final double lat) {

    final JavaScriptObject[] markerArray = new JavaScriptObject[1];  // ugly hack, I know
    dispatch.execute(new GetLocationDescriptionsAction(lng, lat), new AsyncCallback<GetLocationDescriptionsResult>() {
        @Override
        public void onFailure(Throwable caught) {
            caught.printStackTrace();
        }

        @Override
        public void onSuccess(GetLocationDescriptionsResult result) {
            Map<String, Location> resultMap = result.getResult();
            StringBuffer message = new StringBuffer();
            for (String key : resultMap.keySet()) {
                message.append(key).append(": ").append(resultMap.get(key)).append("\n");
            }

            Map tempMap = new HashMap();
            tempMap.put("TITLE","Location Information");
            tempMap.put("LAT", lat);
            tempMap.put("LNG", lng);
            tempMap.put("CONTENTS", message.toString());

            JavaScriptObject marker = GoogleMapUtil.createMarker(tempMap);
            markerArray[0] = marker;
            if (markerArray[0] != null) {
                GWT.log("Marker Array Updated");
            }

        }
    });

    return markerArray[0];
}

更新:根据要求,这里是调用doGetWhereIAmMarker()方法的代码。我尝试过使用一个单独的本地方法,并将Google Map对象(作为JavaScriptObject)作为参数传递,但似乎在本地方法之间传递该对象会导致更新该对象的能力丧失。

public native void initMap(JavaScriptObject mapOptions, JavaScriptObject bounds, JavaScriptObject border, JsArray markerArray, Element e) /*-{

    // create the map and fit it within the given bounds
    map = new $wnd.google.maps.Map(e, mapOptions);
    if (bounds != null) {
        map.fitBounds(bounds);
    }

    // set the polygon for the borders
    if (border != null) {
        border.setMap(map);
    }

    // set up the info windows
    if (markerArray != null && markerArray.length > 0) {
        var infoWindow = new $wnd.google.maps.InfoWindow({
            content:"InfoWindow Content Goes Here"
        });

        for (var i = 0; i < markerArray.length; i++) {
            var marker = markerArray[i];
            marker.setMap(map);
            $wnd.google.maps.event.addListener(marker, 'click', function() {
                infoWindow.setContent(marker.content);
                infoWindow.open(map, this);
            });
        }
    }

    // need to reference the calling class inside the function(), so set a reference to "this"
    var that = this;

   $wnd.whereAmI=function(lng, lat) {
        that.@org.jason.mapmaker.client.view.MapmakerMapViewImpl::whereAmI(DD)(lng,lat);
   }

    $wnd.google.maps.event.addListener(map, 'click', function(event) {
        var lat = event.latLng.lat();
        var lng = event.latLng.lng();
        $wnd.whereAmI(lng, lat);
    });

}-*/;

你能展示更多的代码吗?我对调用这段代码的部分以及消耗从 doGetWhereAmIMarker(...) 返回的 JavaScriptObject 的部分很感兴趣。 - nicholas.hauschild
添加了调用本机方法。GoogleMapUtil位于https://github.com/dartmanx/mapmaker/blob/master/src/main/java/org/jason/mapmaker/client/util/GoogleMapUtil.java,但未提交createMarker()方法。它类似于createMarkerArray()方法。 - Jason
如果你只是放一个 while(asyncIsDone){sleep},为什么它不起作用呢?这似乎是最简单的事情...或者让它成为 for(){sleep},在一定时间后继续执行? - Rohan
2个回答

3

我曾经需要做类似的事情,但最终我通过异步处理的方式消除了那段代码。因此,我无法提供确切的代码供您使用,但只能给出一些指导。

  • 首先,这篇博客描述了如何使用javascript进行同步AJAX。
  • 其次,您必须为同步调用提供支持。问题在于,GWT不支持提供同步AJAX调用的参数。很可能是因为他们不希望鼓励其使用。因此,您需要使用JSNI向XMLHttpRequest(您可能会扩展它)添加适当的方法,然后向RequestBuilder(也应该扩展它)添加方法。
  • 最后,使用扩展的RequestBuilder修改您的服务。类似于

((ServiceDefTarget)service).setRpcRequestBuilder(requestBuilder);

最后,从同一篇博客中摘录(略有不同的上下文):

由于请求丢失并挂起浏览器的危险性,同步javascript不建议在(onbefore)unload事件处理程序之外使用。


我以前做过手动同步 AJAX,但由于这是 GWT,我被限制在 GWT 的限制之内。我正在使用 GWT-Platform 的 DispatchAsync 获取数据,但我没有看到其中使用 RequestBuilder 的任何内容。 - Jason
1
你应该能够使用JSNI将任何Javascript代码与GWT一起使用。当处理RPC时,内部使用RequestBuilder。一旦你拥有了你的服务,你可以使用我提供的片段来分配你自定义的RequestBuilder - Alex Gitelman
我会接受你的答案,因为它很有趣,可能是我某天需要尝试的东西。不过,我已经找到了解决原来问题的答案,这个问题一直阻止我使用异步请求。 - Jason

0

我认为这一切都是命运……
在Gwt中,我们无法捕获响应并发送它,因为请求发送后立即开始执行下一个方法,而不会关心响应。 然而,他们仍然建议我们使用计时器,这是我认为的……

 Timer t = new Timer() {
      @Override
      public void run() {
        Window.alert("Nifty, eh?");
      }
    };
    t.schedule(5000);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接