2016 年 8 月以降の更新
要約すると、この問題に対する現在の正解は、非推奨になったonCameraIdle
の代わりに新しい を使用することです。以下の方法をお読みください。OnCameraChangeListener
これで、「dragEnd」のようなイベントや、最新バージョンの Android 用 Google マップのその他のイベントを聞くことができます。
docsに示されているように、新しいリスナーを使用することで、 の複数 (別名「複数」) の呼び出しの問題を回避できます。OnCameraChangeListener
たとえば、カメラの動きの背後にある理由を確認できるようになりました。これは、fetchData
要求に応じて問題と組み合わせるのに理想的です。次のコードは、主にドキュメントから直接取得したものです。もう1つ、 Google Play サービス 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
このメソッドがトリガーされる頻度が原因で、を使用してサーバーからデータをフェッチするときに問題が発生します。
単純なマップのスライドを行うときにこのメソッドが非常に頻繁にトリガーされるという問題fetchData
が報告されているため、質問の例では、カメラの変更がない場合でも、カメラの変更がほとんどない場合でも、複数の連続した時間をトリガーします。カメラの境界は変更されていませんが、メソッドはトリガーされます。
これは、サーバー側のパフォーマンスに影響を与える可能性があり、サーバーからデータを何十回も連続して取得することで、多くのデバイスのリソースを浪費する可能性があります。
そのリンクでこの問題の回避策を見つけることができますが、それを行う公式の方法はまだありません。たとえば、desirabledragEnd
やcameraChangeEnd
callbacks を使用します。
そこからの例に基づいて、呼び出しの時間間隔を調整し、同じ境界を持つ呼び出しを破棄することで、前述の問題を回避する方法を以下に示します。
// 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;
}