如何在canvas android中的onDraw()方法中快速绘制Bitmap

Gau*_*mar 14 android dictionary canvas bitmap

我试图在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);
        // }
}
Run Code Online (Sandbox Code Playgroud)

yus*_*ulx 21

您应该在Constructor中初始化所有位图.解码位图需要很长时间.您可以使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是我根据您的代码完成的工作.您必须检查一些重复的资源ID.

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);
    // }
}
Run Code Online (Sandbox Code Playgroud)


Sni*_*las 8

优化代码的想法是仅执行绘制所需的操作.所以你应该从你的onDraw方法中删除:

  • 任何instanciation:他们需要很长时间,经常调用onDraw而你不想创建这么多新对象.在onLayout期间存储screenPts并始终重复使用相同的点.
  • BitmapFactory.decodeResource:这需要相当长的时间.首先解码您的位图,存储它们并仅在onDraw期间绘制它们.
  • 当你不再需要它们时回收位图,而不是每次你绘制它们.

例如 :

  • 在onResume期间解码您的位图
  • 在onPause期间回收它们
  • 解码应该在异步任务中进行.当异步任务结束时,引发一个标志以指示onDraw图像已准备好并可以绘制.
  • 在背景中解码图像非常重要,因为它需要很长时间.不要在主UI线程中执行此操作.否则你的应用程序将看起来没有反应
  • 在onLayout中计算你的screenPts并一直重用相同的点.
  • 也不要在onDraw期间调用getIntent.

简而言之,在onDraw期间最小化操作,您将实现非常快速的绘图,大约60 FPS.

您还应该考虑删除那个(丑陋的)开关并使用hashmap将count和要绘制的位图值相关联.数组甚至会更快,也许更合适.

  • @gaurav kumar我认为上面的答案是完整的,不要以为任何代码是必需的.首先,您尝试了解活动生命周期,然后您可以轻松应用上述内容.您应该了解哪种方法以及何时调用它的次数.然后尝试重用您的代码,并始终使用线程或异步任务(在Android中推荐)从UI线程中删除繁重的代码,您就完成了."Snicolas"给出的概念非常通用,可以应用于所有平台. (4认同)