Optimizing the ondraw method of a view

426 views Asked by At

I would like to draw pins for locations on a map. The map is zoomable and pannable thanks to this class in a library I'm using:

https://github.com/davemorrissey/subsampling-scale-image-view.

I extended the subsamplingimageview class to draw images. The resolution of the map is 2494 by 2048 pixels, each pixel is a coordinate. When the activity is visible, only a part of the whole map is visible.

The problem: I need to draw 250 pins on the map, I tried it like this, but zooming and panning the map has a bad performance.

How can I draw the pins on the map without losing performance? I tried drawing the pins on the image bitmap itself, but I can't put the map with pins image in the view unless it's in the assets folder, but this folder is read-only...

protected override void OnDraw(Canvas canvas) 
{
    base.OnDraw(canvas);

    // Don't draw pin before image is ready so it doesn't move around during setup.
    if (!IsImageReady)
    {
        return;
    }

    Paint paint = new Paint();
    paint.AntiAlias = true;

    foreach (Location location in locations)
    {

    if (location != null && pin != null) 
    {
        PointF vPin = SourceToViewCoord(new PointF( (float)location.X    , (float) location.Y    ));
        float vX = vPin.X - (pin.Width/2);
        float vY = vPin.Y - pin.Height;
        canvas.DrawBitmap(pin, vX, vY, paint);
        if (pinPushed) 
        {
            if (location != null && info != null) 
            {
                PointF vInfo = SourceToViewCoord (new PointF( (float)location.X    , (float) location.Y    ));
                float vInfoX = vInfo.X - (info.Width / 2) + (int)ConvertDpToPix(8);//8 pixels cause image is not in the middle
                float vInfoY = vInfo.Y - info.Height;
                //canvas.DrawBitmap (info, vX, vY, paint);
                //float w2 =  info.Width;
                //float h2 =  info.Height;
                canvas.DrawBitmap (textBalloonBitmap, vInfoX, vInfoY, paint);
            }
        }
        }
    }
1

There are 1 answers

0
Jiri Sykora On

I don't know how much is onDraw called in your case but generally more than 1. Therefore is better don't use "new" inside onDraw. But it is just little optimization. Maybe you can check if pin is visible in currently frame (maybe not all 250 pin are visible in same time).

Just example i don't try it.

private Paint paint = new Paint();
private PointF vPin;
private PointF vPinSTVC = PointF();
private PointF vInfo;
private PointF vInfoSTVC = PointF();

protected void OnDraw(Canvas canvas) 
    {
        base.OnDraw(canvas);

        // Don't draw pin before image is ready so it doesn't move around during setup.
        if (!IsImageReady)
        {
            return;
        }

        paint.reset();
        paint.AntiAlias = true;

        foreach (Location location in locations)
        {

        if (location != null && pin != null) 
        {
            vPin = SourceToViewCoord(new PointF( vPinSTVC.set((float)location.X, (float) location.Y));
            float vX = vPin.X - (pin.Width/2);
            float vY = vPin.Y - pin.Height;
            canvas.DrawBitmap(pin, vX, vY, paint);
            if (pinPushed) 
            {
                if (location != null && info != null) 
                {
                    vInfo = SourceToViewCoord (vInfoSTVC.set( (float)location.X    , (float) location.Y));
                    float vInfoX = vInfo.X - (info.Width / 2) + (int)ConvertDpToPix(8);//8 pixels cause image is not in the middle
                    float vInfoY = vInfo.Y - info.Height;
                    //canvas.DrawBitmap (info, vX, vY, paint);
                    //float w2 =  info.Width;
                    //float h2 =  info.Height;
                    canvas.DrawBitmap (textBalloonBitmap, vInfoX, vInfoY, paint);

                }
            }
            }
        }

Next option from documentation (your library) is possible use imageView.setImageUri(".."); maybe you can onstart application draw bitmap and save it on sdcard and use it Uri in setImmageUri.