在我的 Android 应用程序中,我需要知道 MapView 缩放过程何时完成。没有内置的解决方案,所以我有了重写 dispatchDraw 的想法。
只要地图正在缩放(以及在地图上滚动,但这并不重要),就会调用dispatchDraw,我的想法是通过覆盖一个名为dispatchDrawInvoked的变量来不断检查是否调用了dispatchDraw。当第一次调用 MapView 上的缩放时(这意味着缩放过程开始时),我启动了一个新线程,该线程每秒连续将 dispatchDrawInvoked 设置为 false。这个想法是dispatchDraw方法在这一秒内用true覆盖了dispatchDrawInvoked很多次,当第二秒结束并且dispatchDraw仍然为true时,这意味着缩放还没有完成。在大多数情况下,缩放完成并且 dispatchDraw 在循环第二次运行后保持为假,因此至少需要 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;
}
}
}
}
这是始终相同的日志。它表明没有并发: