2012-12-18 14 views
34

C'è un modo semplice per ottenere ildella mappa visibile da un CameraPosition con l'API di Google Maps per Android v2 in modo da poter utilizzare lo OnCameraChangeListener per recuperare nuovi dati per i marcatori.API di Google Maps v2: LatLngBounds da CameraPosition

mMap.setOnCameraChangeListener(new OnCameraChangeListener() { 
      @Override 
      public void onCameraChange(CameraPosition position) { 
       LatLngBounds bounds = ?; 
       fetchNewData(bounds); 
      } 
     }); 

risposta

27

Aggiornamento dal agosto 2016

Sintesi il corretta risposta ora per questo problema è quello di utilizzare la nuova onCameraIdle, invece di OnCameraChangeListener, che ora è deprecated. Leggi sotto come.

Ora puoi ascoltare l'evento "dragEnd" -like e anche altri eventi sulla versione più recente di Google Maps per Android.

Come mostrato nella docs, è possibile evitare il problema della multipla (alias "diversi") chiamate del OnCameraChangeListener utilizzando i nuovi ascoltatori. Ad esempio, ora sei in grado di verificare qual è il motivo dietro il movimento della telecamera, che è l'ideale per accoppiare con un problema fetchData come richiesto. Il seguente codice è per lo più preso direttamente dai documenti. Ancora una cosa, è necessario utilizzare Google Play Services 9.4.

public class MyCameraActivity extends FragmentActivity implements 
     OnCameraMoveStartedListener, 
     OnCameraMoveListener, 
     OnCameraMoveCanceledListener, 
     OnCameraIdleListener, 
     OnMapReadyCallback { 

    private GoogleMap mMap; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_my_camera); 

     SupportMapFragment mapFragment = 
      (SupportMapFragment) getSupportFragmentManager() 
        .findFragmentById(R.id.map); 
     mapFragment.getMapAsync(this); 
    } 

    @Override 
    public void onMapReady(GoogleMap map) { 
     mMap = map; 

     mMap.setOnCameraIdleListener(this); 
     mMap.setOnCameraMoveStartedListener(this); 
     mMap.setOnCameraMoveListener(this); 
     mMap.setOnCameraMoveCanceledListener(this); 

     // Show Sydney on the map. 
     mMap.moveCamera(CameraUpdateFactory 
       .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10)); 
    } 

    @Override 
    public void onCameraMoveStarted(int reason) { 

     if (reason == OnCameraMoveStartedListener.REASON_GESTURE) { 
      Toast.makeText(this, "The user gestured on the map.", 
          Toast.LENGTH_SHORT).show(); 
     } else if (reason == OnCameraMoveStartedListener 
           .REASON_API_ANIMATION) { 
      Toast.makeText(this, "The user tapped something on the map.", 
          Toast.LENGTH_SHORT).show(); 
     } else if (reason == OnCameraMoveStartedListener 
           .REASON_DEVELOPER_ANIMATION) { 
      Toast.makeText(this, "The app moved the camera.", 
          Toast.LENGTH_SHORT).show(); 
     } 
    } 

    @Override 
    public void onCameraMove() { 
     Toast.makeText(this, "The camera is moving.", 
         Toast.LENGTH_SHORT).show(); 
    } 

    @Override 
    public void onCameraMoveCanceled() { 
     Toast.makeText(this, "Camera movement canceled.", 
         Toast.LENGTH_SHORT).show(); 
    } 

    @Override 
    public void onCameraIdle() { 
     Toast.makeText(this, "The camera has stopped moving. Fetch the data from the server!", Toast.LENGTH_SHORT).show(); 
     LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds; 
     fetchData(bounds) 
    } 
} 

Soluzione per una soluzione efficace prima di agosto 2016

Dato che la questione sia adeguatamente risolta, vorrei aggiungere che in una probabilità di essere prossimo numero.

Il problema si pone quando si utilizza OnCameraChangeListener per recuperare i dati dal server a causa della frequenza con cui questo metodo viene attivato.

C'è un issue riferito su come all'impazzata frequente questo metodo viene trigged quando si fa una semplice mappa di scorrimento, quindi nell'esempio della questione, sarebbe innescare fetchData più volte in sequenza per molto piccoli cambiamenti della macchina fotografica, anche per nessuna modifica della fotocamera , sì, succede che i limiti della telecamera non sono cambiati, ma il metodo viene attivato.

Questo potrebbe influire sulle prestazioni lato server e sprecherebbe molte risorse dei dispositivi recuperando i dati in sequenza decine di volte dal server.

È possibile trovare in questo collegamento soluzioni alternative per questo problema, ma non esiste ancora un modo ufficiale per farlo, ad esempio utilizzando i callback desiderabili dragEnd o cameraChangeEnd.

Un esempio qui sotto, basato su quelli da lì, è come evito il suddetto problema giocando con l'intervallo di tempo delle chiamate e scartando le chiamate con gli stessi limiti.

// Keep the current camera bounds 
private LatLngBounds currentCameraBounds; 

new GoogleMap.OnCameraChangeListener() { 
    private static int CAMERA_MOVE_REACT_THRESHOLD_MS = 500; 
    private long lastCallMs = Long.MIN_VALUE; 

    @Override 
    public void onCameraChange(CameraPosition cameraPosition) { 
     LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds; 
     // Check whether the camera changes report the same boundaries (?!), yes, it happens 
     if (currentCameraBounds.northeast.latitude == bounds.northeast.latitude 
     && currentCameraBounds.northeast.longitude == bounds.northeast.longitude 
     && currentCameraBounds.southwest.latitude == bounds.southwest.latitude 
     && currentCameraBounds.southwest.longitude == bounds.southwest.longitude) { 
     return; 
     } 

     final long snap = System.currentTimeMillis(); 
     if (lastCallMs + CAMERA_MOVE_REACT_THRESHOLD_MS > snap) { 
     lastCallMs = snap; 
     return; 
     } 

     fetchData(bounds); 

     lastCallMs = snap; 
     currentCameraBounds = bounds; 

} 
+0

Molto bene! Questo probabilmente mi ha permesso di risparmiare parecchie ore di comprensione del lavoro e quindi di risolvere questo problema. Grazie! – EZDsIt

+0

@EZDsIt sei il benvenuto! – Eduardo

+0

Si dovrebbe anche verificare la presenza di 'null' per il campo' currentCameraBounds'. –

74

Non è possibile ottenere LatLngBound da CameraPosition, ma è possibile ottenerli facilmente da GoogleMap.

private GoogleMap mMap; 

mMap.setOnCameraChangeListener(new OnCameraChangeListener() { 
      @Override 
      public void onCameraChange(CameraPosition position) { 
       LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds; 
       fetchData(bounds); 
      } 
     }); 
+0

mi chiedo perché hanno impostato in quel modo. La regione visibile non dovrebbe avere nulla a che fare con la proiezione della mappa. – capdragon

+4

@capdragon Aspetta, cosa?La proiezione della mappa è precisamente ciò che definisce le 4 coordinate che definiscono la regione visibile – h4lc0n

+1

Immagino che quello che sto dicendo è che non dovrebbero essere accoppiati in questo modo. La regione visibile è semplicemente vincolata indipendentemente dalla proiezione in cui si trova. Non dovrebbe importare se la proiezione è EPSG: 4326 o EPSG: 900913, la vista è la stessa indipendentemente se è in coordinate lat/lon o metri x/y. Quindi si dovrebbe essere in grado di fare 'mMap.getProjection()' o 'mMap.getVisibleRegion()' indipendenti l'uno dall'altro. – capdragon

Problemi correlati