【问题标题】:google maps overlay drawing on canvas from asynctask onPostExecute谷歌地图覆盖画布上的 asynctask onPostExecute
【发布时间】:2012-10-11 18:36:48
【问题描述】:

我有一个谷歌地图 mapView,上面有一个自定义叠加层。此叠加获取用户正在查看的当前坐标,然后转到一个网站,在该网站上获取图像以叠加到地图上。这是一个不好的做法,因为 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];
        }
    }

}

【问题讨论】:

    标签: java android maps android-asynctask overlay


    【解决方案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();
            }
        }       
    
    }
    

    【讨论】:

    • 感谢 DanielGrech。我绝对认为 Canvas 无效,但您的建议似乎没有解决它。我已经编辑了我的代码以反映更新的尝试。您会注意到,我现在将通过 AsyncOverlayData 传递的几乎所有内容都保留为类变量。
    【解决方案2】:

    所以这不是我想要的方式,我不确定谷歌地图的设计方式,但我删除了 AsyncTask,现在在用户与地图交互时自己添加和删除叠加层。

    基本上删除叠加层并在他们触摸地图时设置一个计时器,然后每次如果他们再次触摸并且计时器仍在计数我重置它。如果计时器最终完成,那么我将叠加层重新添加到...


    那么,当您删除 AsyncTask 时,代码是然后放入 Draw 中,还是您必须在 draw 之外覆盖 onPostExecute?

    【讨论】:

      【解决方案3】:

      我认为在 AsycTask 的onPostExecute 方法中使用“thisCanvas”变量是不正确的。您不应该将画布存储在 Overlay 类的成员变量中并在其他方法/内部类中使用它。 canvas 变量只保证在 draw 方法的生命周期内有效。因此,在 AsyncTask 完成后,您应该将生成的图像存储在 Overlay 的成员变量中,然后重新绘制覆盖。如果位置仍然相同,则绘制代码应该只绘制保存的图像。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-01
        • 2021-01-03
        相关资源
        最近更新 更多