【问题标题】:How to draw Bitmap fast in onDraw() method in canvas android如何在画布android的onDraw()方法中快速绘制位图
【发布时间】:2013-11-06 20:03:12
【问题描述】:

我正在尝试在 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);
        // }
}

【问题讨论】:

    标签: android dictionary canvas bitmap


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

    这是我根据您的代码所做的。您必须检查一些重复的资源 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);
        // }
    }
    

    【讨论】:

    • 感谢分享代码。但我认为您不需要第一个示例中的开关。只需这样做:int caller = getIntent().getIntExtra("button", 0); Bitmap bmp = mStore.get(caller); canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); bmp.recycle(); bmp = null; break; }
    【解决方案2】:

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

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

    例如:

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

    简单地说,在 onDraw 期间尽量减少操作,您将实现非常快的绘图,大约 60 FPS。

    您还应该考虑删除那个(丑陋的)开关并使用哈希图来关联计数值和要绘制的位图。数组甚至会更快,也许在这里更合适。

    【讨论】:

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

    您应该从您的draw() 方法中删除所有BitmapFactory.decodeResource() 调用。只解码一次位图并保持对它的引用。然后只需在您的draw() 方法中调用canvas.drawBitmap()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 2013-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      相关资源
      最近更新 更多