0

私の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;
            }
        }
    }
}

これは常に同じログです。これは、並行性がないことを示しています。

ログ

4

1 に答える 1

4

Runnable は、スレッドの作成と実行を処理しません。開始時にスレッドが実行する run() メソッドを提供するだけです。したがって、run() メソッドを同期的に呼び出すだけです。別のスレッドを開始するものを実際に使用する必要があります。

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

ただし、MapThread は実際には単なるランナブルであるため、名前を変更する必要があります。多数のランナブルを投稿するつもりで、すべてのランナブルを作成したくない場合は、 HandlerHandlerThreadに慣れることをお勧めします。

于 2013-02-07T21:26:16.590 に答える