OnCameraChangeListener

OnCameraChangeListener

是否有一种简单的方法可以使用Android Google Maps API v2从LatLngBounds获取可见 map 的CameraPosition,以便我可以使用OnCameraChangeListener来获取标记的新数据。

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

最佳答案

自2016年8月开始更新

概述现在针对此问题的正确答案是使用新的onCameraIdle而不是OnCameraChangeListener(现在为deprecated)。看下面如何。

现在,您可以在最新版本的Android版Google Maps上收听类似“dragEnd”的事件,甚至还可以收听其他事件。

docs所示,您可以通过使用新的监听器来避免对OnCameraChangeListener进行多次(也称为“多次”)调用的问题。例如,您现在可以检查相机移动的背后原因是什么,这是按要求结合fetchData问题的理想选择。以下代码大部分直接来自文档。还有一件事,有必要使用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)
    }
}

解决方案,以在2016年8月之前获得有效的解决方案

当问题得到正确回答后,我想在下一个问题上加以补充。

由于触发此方法的频率,使用OnCameraChangeListener从服务器获取数据时会出现问题。

有一个issue报告了在进行简单的 map 滑动时触发此方法的频繁程度,因此在问题的示例中,即使相机没有更改,它也会连续多次触发oj​​it_code,即使没有相机更改,是的,发生摄影机边界未更改,但是触发了该方法的情况。

这可能会影响服务器端的性能,并且会通过从服务器顺序获取数据数十次来浪费大量设备资源。

您可以在该链接中找到解决此问题的方法,但是还没有一种官方的方法来执行此操作,例如,使用理想的fetchDatadragEnd回调。

下面是一个示例,基于从那里发出的声音,我将如何通过播放通话的时间间隔并丢弃具有相同边界的通话来避免上述问题。
// 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;

}

10-07 13:47