0

在我的 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;
            }
        }
    }
}

这是始终相同的日志。它表明没有并发:

日志

4

1 回答 1

4

Runnable 不负责在线程上创建和执行,它只是提供线程启动时将执行的 run() 方法。所以你只是同步调用 run() 方法。您需要实际使用将启动另一个线程的东西。

new Thread(new MapThread()).start()

会照顾你的意图,但你应该重命名 MapThread 因为它实际上只是一个可运行的,如果你打算发布很多可运行的并且不想为每个线程创建一个线程,我建议你熟悉HandlersHandlerThreads 。

于 2013-02-07T21:26:16.590 回答