(That title alone should cause people to come out of the woodwork to bash me with clubs, but hear me out).
I have a use case where I need to return a value from a asynchronous call. (I'm using GWT-Platform, but the concepts are the same.) I declared a final JavaScriptObject array, then assigned the value within the AsyncCallback. However, I need to return the value, and the method returns before the AsyncCallback completes. Therefore, I need to block somehow until the AsyncCallback completes. I need the returned value in another method, or I'd just do what I need to in onSuccess().
I've tried loops, Timers, and a few other methods with no luck. Can anyone help?
@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];
}
UPDATE: As requested, here is the code that calls doGetWhereIAmMarker(). I've tried having a separate native method with the Google Map object (as a JavaScriptObject) as a parameter, but it appears that passing that object between native methods kills the ability to update said object.
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) {
[email protected]::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);
});
}-*/;
At some point I had to do something similar but eventually I eliminated that code in favor of asynchronous stuff. Therefore, I can't give exact code that you need to use but only few pointers on how to approach it.
XMLHttpRequest
(which you probably would extend) and then to RequestBuilder
(also should extend it).RequestBuilder
. Something like ((ServiceDefTarget)service).setRpcRequestBuilder(requestBuilder);
And in conclusion - from the same blog post (slightly out of context):
Because of the danger of a request getting lost and hanging the browser, synchronous javascript isn't recommended for anything outside of (onbefore)unload event handlers.