【问题标题】:Android: Canvas.DrawBitmap VS Drawable.Draw - Huge performance boostAndroid:Canvas.DrawBitmap VS Drawable.Draw - 巨大的性能提升
【发布时间】:2011-05-16 20:04:17
【问题描述】:

我刚刚发现了一些东西,我想知道如何以及为什么。 我正在为 Android 开发一款小型街机游戏。我决定忽略 OpenGL 并使用标准的 SurfaceView 和 Drawables 来完成它,因为它应该很轻(大约 10 个精灵)。 我有我加载的可绘制对象,我使用方法 Draw 并将它们传递给我的画布。这就是每个精灵被绘制到屏幕上的方式。 事实证明,在非全新手机型号上绘制 4-5 个大精灵(200X400 左右)需要很长时间。足够长的时间让我的游戏无法玩。我们正在谈论使用此方法绘制单个帧需要 50-60 毫秒。除了画画,我真的什么都不做,我无处可以削减成本。所以我决定尝试使用位图。然而,在这里,我需要预先设置大小,因为位图中没有“setBounds”方法。没问题,我在加载时调整它们的大小以适应我当前的屏幕,问题解决了。

好的。所以我得到了位图。我现在使用 Canvas.DrawBitmap 进行绘制。我对新的绘制方法进行了测试。我得到了惊人的 400% 性能提升!整个绘制循环现在需要 8-12 毫秒,而不是 50-60 毫秒。 什么鬼?? 为了排除它,我也对 setBounds 进行了计时,它需要

对我来说这是个好消息,因为我真的不想学习 OpenGL 来让我的游戏可玩,但我不禁想知道 - 可以吗?我的方法有问题吗?为什么在任何地方都没有提到它?

【问题讨论】:

  • 这听起来不错,但如果您运行实际的测试代码来验证结果可能会很好......

标签: android


【解决方案1】:

Canvas 中的 SurfaceView 是在您应该不断迭代时使用的,而 Drawable 不是用于此目的。

【讨论】:

  • 这是我使用的同一个画布对象,canvas.drawBitmap 或 Drawable.Draw(canvas)。在这两种情况下,它都是从 SurfaceView 派生的画布,因此无论哪种方式,它都是您正在使用的 surfaceView。您无需在 Drawabls 和 SurfaceView 之间进行选择 - 您可以使用 Drawables with SurfaceView。这就是 Google 的“快速游戏”(例如月球着陆器)代码示例的工作原理。
【解决方案2】:

Canvas.drawBitmap 的工作量比 Drawable.draw 少很多,因此速度更快。

Drawable.draw

由于Drawable是一个抽象类,我们来看看BitmapDrawable

BitmapDrawable.draw(canvas)

public void draw(Canvas canvas) {
    final Bitmap bitmap = mBitmapState.mBitmap;
    if (bitmap == null) {
        return;
    }
    final BitmapState state = mBitmapState;
    final Paint paint = state.mPaint;
    if (state.mRebuildShader) {
        final Shader.TileMode tmx = state.mTileModeX;
        final Shader.TileMode tmy = state.mTileModeY;
        if (tmx == null && tmy == null) {
            paint.setShader(null);
        } else {
            paint.setShader(new BitmapShader(bitmap,
                    tmx == null ? Shader.TileMode.CLAMP : tmx,
                    tmy == null ? Shader.TileMode.CLAMP : tmy));
        }
        state.mRebuildShader = false;
    }
    final int restoreAlpha;
    if (state.mBaseAlpha != 1.0f) {
        final Paint p = getPaint();
        restoreAlpha = p.getAlpha();
        p.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
    } else {
        restoreAlpha = -1;
    }
    final boolean clearColorFilter;
    if (mTintFilter != null && paint.getColorFilter() == null) {
        paint.setColorFilter(mTintFilter);
        clearColorFilter = true;
    } else {
        clearColorFilter = false;
    }
    updateDstRectAndInsetsIfDirty();
    final Shader shader = paint.getShader();
    final boolean needMirroring = needMirroring();
    if (shader == null) {
        if (needMirroring) {
            canvas.save();
            // Mirror the bitmap
            canvas.translate(mDstRect.right - mDstRect.left, 0);
            canvas.scale(-1.0f, 1.0f);
        }
        canvas.drawBitmap(bitmap, null, mDstRect, paint);
        if (needMirroring) {
            canvas.restore();
        }
    } else {
        updateShaderMatrix(bitmap, paint, shader, needMirroring);
        canvas.drawRect(mDstRect, paint);
    }
    if (clearColorFilter) {
        paint.setColorFilter(null);
    }
    if (restoreAlpha >= 0) {
        paint.setAlpha(restoreAlpha);
    }
}

你可以看到它甚至在内部调用了canvas.drawBitmap

Canvas.drawBitmap

将其与Canvas.drawBitmap 进行比较。它要短得多。

Canvas.drawBitmap

public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
    throwIfCannotDraw(bitmap);
    native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top,
            paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
}

有几种不同的drawBitmap 方法,但它们都比Drawable.draw 方法短。注意陷阱like this 以保持您的位图绘制速度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-21
    • 2010-10-15
    • 2013-02-18
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    相关资源
    最近更新 更多