1

カスタムオーバーレイを持つGoogleマップのmapViewがあります。このオーバーレイは、ユーザーが見ている現在の座標を取得し、Web サイトに移動して、マップ上にオーバーレイする画像を取得します。Web リクエストには数秒かかり、UI スレッドが完全にロックされる可能性があるため、これは悪い習慣です。その問題を修正しようとしています。

画像を取得し、準備ができたらマップに描画する AsyncTask を使用して修正しようとしています。Canvas を AsyncTask に渡して、準備ができたときに描画が行われるようにしようとしていますが、描画が行われず、描画時にキャンバスのサイズが 0x0 であることがわかります。

AsyncTask に入れようとする前に、すべての描画コードが機能していましたが、それが遅かっただけです。

これはすべて私のカスタム オーバーレイにあります。

public class MapOverlaySevereWeather extends com.google.android.maps.Overlay
{
    private GeoPoint lastTopLeft = new GeoPoint(0, 0);
    private GeoPoint lastBotRight = new GeoPoint(0, 0);
    private Bitmap mapImage;
    private Canvas thisCanvas;
    private MapView mMapView;

    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow)
    {
        super.draw(canvas, mapView, shadow);

        if( shadow || MapOverlayHandler.isInMotion() )
        { return; }

        mMapView = mapView;
        thisCanvas = canvas;
        Rect curShown = canvas.getClipBounds();
        GeoPoint topLeft = mapView.getProjection().fromPixels(0,0);
        GeoPoint bottomRight = mapView.getProjection().fromPixels(curShown.right, curShown.bottom);

        if( !topLeft.equals(lastTopLeft) || !bottomRight.equals(lastBotRight) )
        {
            int sizeX = mapView.getWidth();//curShown.right - curShown.left;
            int sizeY = mapView.getHeight();////curShown.bottom - curShown.top;
            float minLat = (float)bottomRight.getLatitudeE6() / 1E6f;
            float minLon = (float)topLeft.getLongitudeE6() / 1E6f;
            float maxLat = (float)topLeft.getLatitudeE6() / 1E6f;
            float maxLon = (float)bottomRight.getLongitudeE6() / 1E6f;
            String fileUrl = "url that gets image based off lat long size";

            new SevereWeatherAsync().execute(new AsyncOverlayData(fileUrl, canvas, curShown));
        }

        lastTopLeft = topLeft;
        lastBotRight = bottomRight;
        return;
    }

    private class SevereWeatherAsync extends AsyncTask<AsyncOverlayData, Void, AsyncOverlayData>
    {
        @Override
        protected void onPostExecute(AsyncOverlayData result)
        {
            super.onPostExecute(result);
            Log.w("Severe","Drawing on " + thisCanvas.getHeight() + " x " + thisCanvas.getWidth());
            Paint paint = new Paint();
            paint.setAlpha(100);        
            thisCanvas.drawBitmap(mapImage, null, result.getCurRect(), paint);
            mMapView.invalidate();
        }

        @Override
        protected AsyncOverlayData doInBackground(AsyncOverlayData... params)
        {
            Log.w("Severe","getting image");
            URL imageFileURL = null;       
            try
            {
                imageFileURL = new URL(params[0].getURL());
                HttpURLConnection conn = (HttpURLConnection) imageFileURL.openConnection();
                conn.setDoInput(true);
                conn.connect();
                InputStream is = conn.getInputStream();
                mapImage = BitmapFactory.decodeStream(is);
            }
            catch(Exception e)
            { return null; }        

            return params[0];
        }
    }

}
4

3 に答える 3

1

AsyncTask に渡したキャンバスが、画像がダウンロードされるまでに無効になっていることが原因だと思います。

result.getImage() から返されたビットマップをインスタンス変数に保存してから、オーバーレイ自体を再描画することをお勧めします。

したがって、次のようなものがあります..

public class MyOverlay extends Overlay {
    private Bitmap mBitmap;
    private MapView mMapView;

    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        // .. your drawing code
        if(mBitmap == null) {
            // Better download your image!
            new SevereWeatherAsync().execute(new AsyncOverlayData(fileUrl, void, curShown));
        } else {
            //Draw the bitmap!
            canvas.drawBitmap(mBitmap, ...);
        }
    } 

    private class SevereWeatherAsync extends AsyncTask<> {
        @Override
        protected AsyncOverlayData doInBackground(AsyncOverlayData... params) {
            //You background work..
        }

        @Override
        protected void onPostExecute(AsyncOverlayData result) {
            mBitmap = result.getImage();

            //Now we can redraw the overlay!
            mMapView.invalidate();
        }
    }       

}
于 2012-05-17T02:45:50.950 に答える
0

AsycTaskのメソッドで「thisCanvas」変数を使用するのonPostExecuteは正しくないと思います。キャンバスをOverlayクラスのメンバー変数に格納し、他のメソッド/内部クラスで使用しないでください。キャンバス変数は、drawメソッドの存続期間中のみ有効であることが保証されています。したがって、AsyncTaskが完了したら、結果の画像をオーバーレイのメンバー変数に格納してから、オーバーレイを再描画する必要があります。場所が同じであれば、描画コードは保存された画像を描画するだけです。

于 2012-07-03T18:25:48.990 に答える
0

したがって、これは私が望んでいた方法ではなく、Google マップが設計された方法であるかどうかはわかりませんが、AsyncTask を削除し、ユーザーがマップを操作しているときにオーバーレイ自体を追加および削除しています。

基本的にオーバーレイを削除し、マップに触れたときにタイマーを設定し、その後、もう一度触れてもタイマーがまだカウントされている場合はリセットします。タイマーが最終的に完了したら、オーバーレイを元に戻します...


AsyncTask を削除すると、コードが Draw に配置されましたか、それとも draw の外で onPostExecute をオーバーライドする必要がありましたか?

于 2012-05-17T19:50:33.287 に答える