Как быстро нарисовать битмап в методе onDraw() в canvas android

Я пытаюсь нарисовать маркер по методу единственного крана в android. когда я рисую маркер, он будет рисовать, но потребуется больше времени, чтобы нарисовать в течение 30-40 миллисекунд несколько раз, это занимает 2-3 секунды. Вот мой код для класса, в котором у меня есть метод draw.

public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem> {

    private ArrayList<OverlayItem> overlayItemList = new ArrayList<OverlayItem>();

    public MyItemizedOverlay(Drawable pDefaultMarker,
            ResourceProxy pResourceProxy) {
        super(pDefaultMarker, pResourceProxy);
    }

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

        // ---translate the GeoPoint to screen pixels---
        Point screenPts = new Point();
        mapView.getProjection().toPixels(p, screenPts);

        // ---add the marker---
        Bitmap bmp = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_darkblue);
        Bitmap bmp1 = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_green);
        Bitmap bmp2 = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_bue);
        Bitmap bmp3 = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_light);
        Bitmap bmp4 = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_light);
        Bitmap bmp5 = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_light);
        Bitmap bmp6 = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_light);
        if (count == 1) {
            int caller = getIntent().getIntExtra("button", 0);
            switch (caller) {
            case R.id.btMap:
                canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
                bmp.recycle();
                break;
            case R.id.imageButton1:
                canvas.drawBitmap(bmp1, screenPts.x, screenPts.y - 50, null);
                bmp1.recycle();
                break;
            case R.id.imageButton2:
                canvas.drawBitmap(bmp2, screenPts.x, screenPts.y - 50, null);
                bmp2.recycle();
                break;
            case R.id.imageButton3:
                canvas.drawBitmap(bmp3, screenPts.x, screenPts.y - 50, null);
                bmp3.recycle();
                break;
            case R.id.imageButton4:
                canvas.drawBitmap(bmp4, screenPts.x, screenPts.y - 50, null);
                bmp4.recycle();
                break;
            case R.id.imageButton5:
                canvas.drawBitmap(bmp5, screenPts.x, screenPts.y - 50, null);
                bmp5.recycle();
                break;
            case R.id.imageButton6:
                canvas.drawBitmap(bmp6, screenPts.x, screenPts.y - 50, null);
                bmp6.recycle();
                break;
            }
        }
        // Bitmap bmp = BitmapFactory.decodeResource(getResources(),
        // R.drawable.pin_annotation_green);
        // if (count == 1) {
        // canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
        // }
}

Ответы

Ответ 1

Вы должны инициализировать все растровые изображения в конструкторе. Растровое изображение декодирования занимает много времени. Вы можете использовать HashMap (ключ, значение) для их хранения. Затем в onDraw получите согласованное растровое изображение и нарисуйте его напрямую.

Например

public class MyView extends View{

    private HashMap<String, Bitmap> mStore = new HashMap<String, Bitmap>();
    public MyView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub

        init();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub

        int caller = getIntent().getIntExtra("button", 0);
        Bitmap bmp = null;
        switch (caller) {
        case R.id.btMap:
            bmp = mStore.get(R.id.btMap);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            bmp = null;
            break;
        case R.id.imageButton1:
            bmp = mStore.get(R.id.imageButton1);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp1.recycle();
            bmp1 = null;
            break;
        }

        super.onDraw(canvas);
    }

    public void init() {
        Bitmap bmp = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_darkblue);
        mStore.put(R.id.btMap, bmp);

        bmp = BitmapFactory.decodeResource(getResources(),
                R.drawable.pin_annotation_green);
        mStore.put(R.id.imageButton1, bmp);
    }
}

Вот что я сделал на основе вашего кода. Вы должны проверить некоторые дублированные идентификаторы ресурсов.

private ArrayList<OverlayItem> overlayItemList = new ArrayList<OverlayItem>();
private HashMap<String, Bitmap> mStore = new HashMap<String, Bitmap>();

public MyItemizedOverlay(Drawable pDefaultMarker,
        ResourceProxy pResourceProxy) {
    super(pDefaultMarker, pResourceProxy);

    Bitmap bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_darkblue);
    mStore.put(R.id.btMap, bmp);
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_green);
    mStore.put(R.id.imageButton1, bmp);
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_bue);
    mStore.put(R.id.imageButton2, bmp);
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_light); 
    mStore.put(R.id.imageButton3, bmp);
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_light); // check it
    mStore.put(R.id.imageButton4, bmp);
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_light); // check it
    mStore.put(R.id.imageButton5, bmp);
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.pin_annotation_light); // check it
    mStore.put(R.id.imageButton6, bmp);

}

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

    // ---translate the GeoPoint to screen pixels---
    Point screenPts = new Point();
    mapView.getProjection().toPixels(p, screenPts);

    // ---add the marker---
    if (count == 1) {
        int caller = getIntent().getIntExtra("button", 0);
        Bitmap bmp = null;

        switch (caller) {
        case R.id.btMap:
            bmp = mStore.get(R.id.btMap);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        case R.id.imageButton1:
            bmp = mStore.get(R.id.imageButton1);
            canvas.drawBitmap(bmp1, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        case R.id.imageButton2:
            bmp = mStore.get(R.id.imageButton2);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        case R.id.imageButton3:
            bmp = mStore.get(R.id.imageButton3);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        case R.id.imageButton4:
            bmp = mStore.get(R.id.imageButton4);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        case R.id.imageButton5:
            bmp = mStore.get(R.id.imageButton5);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        case R.id.imageButton6:
            bmp = mStore.get(R.id.imageButton6);
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
            bmp.recycle();
            break;
        }
    }
    // Bitmap bmp = BitmapFactory.decodeResource(getResources(),
    // R.drawable.pin_annotation_green);
    // if (count == 1) {
    // canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null);
    // }
}

Ответ 2

Идея оптимизации вашего кода - выполнять только операции, необходимые для рисования. Таким образом, вы должны удалить из метода onDraw:

  • любое instanciation: они занимают много времени, onDraw вызывается часто, и вы не хотите создавать так много новых объектов. Храните экранные окна во время onLayout и повторно используйте одни и те же точки, всегда.
  • BitmapFactory.decodeResource: это занимает довольно много времени. Сначала декодируйте растровое изображение, сохраните их и нарисуйте только во время onDraw.
  • переработайте растровые изображения, когда они вам больше не понадобятся, а не каждый раз, когда вы их нарисовали.

Например:

  • декодировать ваши растровые изображения во время onResume
  • утилизировать их во время onPause
  • декодирование должно происходить внутри задачи async. Когда задача async завершена, поднимите флаг, чтобы указать onDraw, что изображения готовы и могут быть нарисованы.
  • Очень важно декодировать изображения в фоновом режиме, поскольку это занимает много времени. Не делайте этого в главной теме пользовательского интерфейса. В противном случае ваше приложение будет выглядеть невосприимчивым.
  • вычислить ваши экраны внутри onLayout и повторно использовать одни и те же точки все время.
  • не вызывайте getIntent во время onDraw.

Вкратце, свести к минимуму операции во время onDraw, и вы достигнете очень быстрого рисования около 60 FPS.

Вы также должны рассмотреть возможность удаления этого (уродливого) переключателя и использовать хэш-карту для сопоставления значений count и растрового изображения для рисования. Массив будет даже быстрее и, возможно, более уместен.

Ответ 3

Вы должны удалить все вызовы BitmapFactory.decodeResource() из вашего метода draw(). Декодируйте растровое изображение только один раз и продолжайте ссылаться на него. Затем просто вызовите canvas.drawBitmap() в свой метод draw().