2016-05-12 6 views
9

Ich zeige eine Wetterkarte in einer GWT-Anwendung. Ich verwende GWT 2.7 und den GWT-Wrapper der GoogleMaps JavaScript API here (gwt-maps-3.8.0-pre1.zip).Refreshing GoogleMaps Kachelserver funktioniert in JavaScript, aber nicht in GWT

Ich verwende einen Kachelserver, um das Wetter abzurufen, das alle 5 Minuten aktualisiert wird. In der 5-Minuten-Marke aktualisiere ich die Karte, indem ich den Zoom auf 1 und dann auf das Original zurückstelle, indem ich eine Größenänderung auslöst und die Wetterebene entferne und dann wieder hinzufüge.

Das hat gut funktioniert. Allerdings habe ich kürzlich festgestellt, dass dies nicht mehr funktioniert: Die Aktualisierung geht nicht einmal auf den Kachelserver, sodass kein neues Wetter angezeigt wird. Wenn Sie meine Karte für 12 Stunden verlassen, werden Sie 12 Stunden altes Wetter sehen. Zuvor wurde die Karte automatisch aktualisiert. Ich habe nichts von meinem Code geändert. Also meine Vermutung ist, dass sich etwas in der zugrunde liegenden GoogleMaps JavaScript API geändert hat.

Allerdings Ich habe dann diese einfache reine JavaScript-Beispiel:

<!DOCTYPE html> 
<html> 
    <head> 
     <title>Map Test</title> 
     <style type="text/css"> 
      html, body { height: 100%; margin: 0; padding: 0; } 
      #map { 
       width:90%; 
       height: 90%; 
       display:inline-block; 
      } 
     </style> 
    </head> 
<body> 
<div id="map"></div> 
<button type="button" onClick="refreshMap()">Refresh</button> 
<script type="text/javascript"> 

    var map; 
    var tileNEX; 

    function initMap() { 

     var mapOptions = { 
      zoom: 8, 
      center: new google.maps.LatLng(42.5, -95.5), 
      mapTypeId: google.maps.MapTypeId.ROADMAP 
     }; 

     map = new google.maps.Map(document.getElementById('map'), mapOptions); 

     tileNEX = new google.maps.ImageMapType({ 
      getTileUrl: function(tile, zoom) { 
       return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/" + zoom + "/" + tile.x + "/" + tile.y +".png?"+ (new Date()).getTime(); 
      }, 
      tileSize: new google.maps.Size(256, 256), 
      opacity:0.60, 
      name : 'NEXRAD', 
      isPng: true 
     }); 

     map.overlayMapTypes.setAt("0",tileNEX); 
    } 

    function refreshMap(){ 
     var zoom = map.getZoom(); 
     map.setZoom(1); 
     map.setZoom(zoom); 

     //google.maps.event.trigger(map, 'resize'); 

     //var layer = map.overlayMapTypes.getAt(0); 
    //map.overlayMapTypes.setAt(0, null); 
    //map.overlayMapTypes.setAt(0, layer); 
    } 

</script> 
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"> 
</script> 
</body> 
</html> 

Zu meiner Überraschung, das funktioniert noch in Ordnung. Wenn Sie auf die Schaltfläche Aktualisieren klicken, wird die Karte zum Kachelserver geleitet und neue Kacheln abgerufen.

So habe ich versucht, die genau die gleiche Sache in GWT tun:

package com.example.client; 

import com.google.gwt.ajaxloader.client.AjaxLoader; 
import com.google.gwt.ajaxloader.client.AjaxLoader.AjaxLoaderOptions; 
import com.google.gwt.core.client.EntryPoint; 
import com.google.gwt.dom.client.Document; 
import com.google.gwt.event.dom.client.ClickEvent; 
import com.google.gwt.event.dom.client.ClickHandler; 
import com.google.gwt.user.client.ui.Button; 
import com.google.gwt.user.client.ui.RootPanel; 
import com.google.maps.gwt.client.GoogleMap; 
import com.google.maps.gwt.client.LatLng; 
import com.google.maps.gwt.client.MapOptions; 
import com.google.maps.gwt.client.MapType; 
import com.google.maps.gwt.client.MapTypeId; 

public class GwtMapTest implements EntryPoint { 

    @Override 
    public void onModuleLoad() { 
     AjaxLoaderOptions options = AjaxLoaderOptions.newInstance(); 
     options.setOtherParms("sensor=false"); 
     Runnable callback = new Runnable() { 
      public void run() { 
       createMap(); 
      } 
     }; 
     AjaxLoader.loadApi("maps", "3", callback, options); 
    } 

    public void createMap() { 

     MapOptions mapOpts = MapOptions.create(); 
     mapOpts.setZoom(4); 
     mapOpts.setCenter(LatLng.create(37.09024, -95.712891)); 
     mapOpts.setMapTypeId(MapTypeId.TERRAIN); 
     mapOpts.setStreetViewControl(false); 

     final GoogleMap map = GoogleMap.create(Document.get().getElementById("map_canvas"), mapOpts); 
     addWeatherLayer(map); 

     Button button = new Button("Gwt Refresh"); 
     button.addClickHandler(new ClickHandler(){ 

      @Override 
      public void onClick(ClickEvent event) { 
       refreshWeatherLayer(map); 
      } 
     }); 

     Button nativeButton = new Button("Native Refresh"); 
     nativeButton.addClickHandler(new ClickHandler(){ 

      @Override 
      public void onClick(ClickEvent event) { 
       nativeRefreshWeatherLayer(map); 
      } 
     }); 

     RootPanel.get().add(button); 
     RootPanel.get().add(nativeButton); 
    } 

    public native void addWeatherLayer(GoogleMap map) /*-{ 
     var imageMapType = new $wnd.google.maps.ImageMapType({ 
      getTileUrl: function(coord, zoom) { 
       return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/"+ zoom + "/" + coord.x + "/" + coord.y + ".png"; 
      }, 
      tileSize: new $wnd.google.maps.Size(256, 256), 
      opacity:.50, 
      isPng: true 
     }); 

     map.overlayMapTypes.setAt("0", imageMapType); 

    }-*/; 

    private void refreshWeatherLayer(GoogleMap map){ 
     double zoom = map.getZoom(); 
     map.setZoom(1); 
     map.setZoom(zoom); 

     MapType layer = map.getOverlayMapTypes().getAt(0); 
     map.getOverlayMapTypes().setAt(0, null); 
     map.getOverlayMapTypes().setAt(0, layer); 
    } 

    private native void nativeRefreshWeatherLayer(GoogleMap map) /*-{ 
     var zoom = map.getZoom(); 
     map.setZoom(1); 
     map.setZoom(zoom); 

     $wnd.google.maps.event.trigger(map, 'resize'); 

     var layer = map.overlayMapTypes.getAt(0); 
     map.overlayMapTypes.setAt(0, null); 
     map.overlayMapTypes.setAt(0, layer); 
    }-*/; 

} 

Dies sollte das gleiche wie das reine JavaScript Beispiel tun. Wenn ich stattdessen auf die Schaltfläche klicke, wird die Karte aktualisiert (ich sehe, dass die Wetterebene blinkt), , aber sie geht nicht auf den Kachelserver für neue Kacheln.

Weider immer noch funktioniert diese "sorta" im Internet Explorer: vielleicht 1 von 3 mal klicke ich auf die Schaltfläche, die Karte geht tatsächlich auf den Kachelserver. In Chrome geht es jedoch nie auf den Kachelserver, wenn ich auf die Schaltfläche klicke.

Um dies zu ermitteln, schaue ich auf die Registerkarte Netzwerk der Browser-Tools. Ich würde erwarten, dass die Karte den Kachelserver jedes Mal trifft, wenn ich auf die Schaltfläche klicke. Das ist, was es in reinem JavaScript macht, und das war es, was es in GWT getan hat, aber irgendwann in den letzten paar Monaten hat sich das GWT-Verhalten geändert.

Ich glaube nicht, dass dies ein Browser-Caching-Problem ist. Das Problem ist nicht, dass die Karte versucht, neue Fliesen zu holen, aber alte bekommt, ist es, dass es nie versucht, neue Fliesen zu holen. Ich klicke auf die Schaltfläche, und auf der Netzwerkregisterkarte der Entwicklerwerkzeuge passiert nichts.

  • Warum sehe ich ein anderes Verhalten in JavaScript vs GWT?
  • Warum sehe ich ein anderes Verhalten in verschiedenen Browsern?
  • Führt die GWT GoogleMaps-Bibliothek eine Art internes Caching durch? Gibt es eine Möglichkeit, dies zu deaktivieren?
  • Warum hat sich dieses Verhalten anscheinend geändert?
  • Wie kann ich die GWT-Karte aktualisieren, indem ich für neue Kacheln zum Kachelserver gehe?
+0

Ich habe das Skript in beiden Browsern getestet und es auf GWT versucht. Einer der Unterschiede, die ich fand, ist, dass sie in den Browsern einen Zeitstempel nach der Kachel setzen (/ZOOM/X/Y.png?TIME). Der GWT-Code tut das anscheinend nicht. Im Browser, wenn die Zeit verstrichen ist, ruft IE sie vom Server ab, und Chrome holt sie von localcache. Möglicherweise war die Änderung in dem Kachelserver (oder einem bestimmten Proxy), der die Kachel zwischenspeichert. Können Sie versuchen, die Anfrage im GWT-Code mit einem "? TIME" -Param zu aktualisieren? – fhofmann

+0

@fhofmann Das hat tatsächlich funktioniert, was für mich überraschend ist. Normalerweise fügen Sie einen "Zeit" -Teil hinzu, um den Browser-Cache zu vermeiden, was in diesem Fall nicht das Problem war, da er niemals zum Server gegangen ist und daher niemals den Browser-Cache überprüft hat. Es sieht also so aus, als müsste es ein internes Caching geben, aber nur in der GWT-Version, was für mich keinen Sinn ergibt. Kannst du erklären, warum die GWT- und JS-Versionen anders sind oder warum die "Zeit" in GWT funktioniert? Wenn Sie das als Antwort hinzufügen möchten, würde ich es definitiv zu schätzen wissen. –

+0

Eigentlich habe ich GWT vorher noch nie benutzt. Aber jetzt bin ich neugierig und ich werde versuchen zu finden, wie es funktioniert und wo es Caching sein könnte. – fhofmann

Antwort

1

Dies ist nicht die endgültige Antwort. Enthält jedoch wichtige Informationen.

http So verwalten Sie ruft GWT eine Reihe von Klassen, die wie ein Browser handeln, und ist, wo ich das Problem ist, glauben.

Wenn derselbe Code zuvor funktioniert hat, ist es möglich, dass der Kachelserver kürzlich den Cache-Header (Cache-Control: max-age = 300) enthält. Und aus irgendeinem Grund verwaltet der GWT-Code diesen Header nicht richtig.

Wenn ich Recht habe, ein Weg, um das Problem zu vertreiben ist ein Parameter, der mit der aktuellen Zeit in der GWT Aufruf anhängen (wie die Browser-Version des Codes).

public native void addWeatherLayer(GoogleMap map) /*-{ 
    var imageMapType = new $wnd.google.maps.ImageMapType({ 
     getTileUrl: function(coord, zoom) { 
      return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/"+ zoom + "/" + coord.x + "/" + coord.y + ".png?" + new Date().getTime(); 
     }, 
     tileSize: new $wnd.google.maps.Size(256, 256), 
     opacity:.50, 
     isPng: true 
    }); 

    map.overlayMapTypes.setAt("0", imageMapType); 

}-*/; 
+0

Sie haben die richtige Lösung, aber ich denke nicht, dass das Problem in GWT ist. Das ist meine Schuld, da mir nicht klar war, dass ich in meiner JavaScript-Version den '' time''-Teil hatte. Wenn ich das herausnehme, verhält es sich wie die GWT-Version. Wenn ich es zur GWT-Version hinzufüge, dann funktioniert es perfekt. ** Das Problem liegt also in der zugrunde liegenden JavaScript-Bibliothek, nicht in GWT. ** Offenbar führt Google Maps internes Caching durch, was auch bedeutet, dass ** das Ändern der Cache-Kontrolle des Kachelservers nichts bewirkt. ** I ' Ich bin mir ziemlich sicher, dass dies ein neues Verhalten ist, aber ich kann es nicht sagen, da der Code verschleiert ist. –

+0

Das heißt, Sie haben den "Zeit" -Teil in meinem JavaScript aufgezeigt, also verdienen Sie das Kopfgeld. Das war eine große Hilfe. Aber ich glaube nicht, dass wir die Ursache des Problems identifiziert haben, da es sich um die Google Map API handelt, die verschleiert ist. Ich würde gerne ein offizielles Wort darüber hören, ob sich etwas nur für meine eigene geistige Gesundheit geändert hat, aber im Moment funktioniert das so, dass ich glücklich bin. –

+0

Ich habe einen anderen Test gemacht. Dieses Mal habe ich den GWT-Code kompiliert und auf einen gefälschten Kachelserver (lokales Servlet, das die aktuelle Zeit in einem Bild zurückgibt) gezeigt. Mein Ziel war es, zu beweisen, dass der Cache-Header das Problem ist und zu sehen, wo GWT das Bild herunterladen und verwalten. Leider erhalte ich einen Skriptfehler und kann Ihre Anwendung nicht sehen. – fhofmann