私のAndroidアプリでは、MapViewのズームプロセスがいつ終了したかを知る必要があります。そのための組み込みのソリューションがないため、dispatchDrawをオーバーライドすることを考えました。
マップがズームしている間(およびマップ上をスクロールしている間)、dispatchDrawが呼び出されます。私の考えは、dispatchDrawInvokedという変数を上書きしてdispatchDrawが呼び出されるかどうかを継続的にチェックすることです。MapViewのズームが最初に呼び出されたとき(つまり、ズームプロセスが開始されたとき)、dispatchDrawInvokedを毎秒falseに継続的に設定する新しいスレッドを開始します。この考え方は、dispatchDrawメソッドがこの1秒以内にdispatchDrawInvokedをtrueで何度も上書きし、2番目が終了してもdispatchDrawがtrueの場合、ズームがまだ終了していないことを意味します。ほとんどの場合、ループが2回実行された後、ズームは終了し、dispatchDrawはfalseのままなので、少なくとも2秒かかります。
ここまでは順調ですね。問題は、この実装全体が同時に動作しないことです。シーケンシャルに動作し、MapViewが2秒間スタックします。なぜそうなのか、私のコードを見てください:
public class ZoomListeningMapView extends MapView {
private final static String TAG = ZoomListeningMapView.class.getSimpleName();
private final static int DEFAULT_ZOOM_LEVEL = 14;
private int lastZoomLevel = DEFAULT_ZOOM_LEVEL;
private volatile boolean zooming = false;
private volatile boolean dispatchDrawInvoked = false;
public ZoomListeningMapView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ZoomListeningMapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ZoomListeningMapView(Context context, String apiKey) {
super(context, apiKey);
}
public boolean isZooming() {
return zooming;
}
public static int getDefaultZoomLevel() {
return DEFAULT_ZOOM_LEVEL;
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
dispatchDrawInvoked = true;
Log.i(TAG, "setting dispatchDrawInvoked to true");
Log.i(TAG, "zooming:" + zooming);
if (getZoomLevel() != lastZoomLevel) {
lastZoomLevel = getZoomLevel();
Log.i(TAG, "zoom level changed");
zooming = true;
Log.i(TAG, "zooming:" + zooming);
new Thread(new ZoomRunnable()).start();
}
}
private class ZoomRunnable implements Runnable {
private final String TAG = ZoomRunnable.class.getSimpleName();
@Override
public void run() {
try {
while (zooming) {
dispatchDrawInvoked = false;
Log.i(TAG, "setting dispatchDrawInvoked to false");
Thread.sleep(1000);
if (dispatchDrawInvoked == false) {
zooming = false;
Log.i(TAG, "dispatchDrawInvoked is still false, so Map zooming is finished.");
}
}
}
catch (InterruptedException e) {
Log.e(TAG, "InterruptedException: " + e.getMessage());
return;
}
}
}
}
これは常に同じログです。これは、並行性がないことを示しています。