【问题标题】:Android, fastest way to draw a bitmap to canvasAndroid,将位图绘制到画布的最快方法
【发布时间】:2011-10-14 22:53:33
【问题描述】:

只是想知道在画布上绘制位图最快的方法是什么?

目前我有一个位图(和用于绘图的画布),我用它来双缓冲绘图调用,然后当我绘制到画布时,通过应用 1px 画布平移来产生滚动效果。仅此一项就可以将帧率从 60+ FPS 降低到 ~40,非常受欢迎。我目前没有使用surfaceView(或GLSurfaceView),只是想知道我是否遗漏了任何可以提高速度的东西。 onDraw() 代码如下

@Override
    public void onDraw(Canvas canvas)
    {
        //update fps text
        mFpsTracker.frameTouch();

        if(mBufferedBitmap == null)
        {
            mBufferedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
            mBufferedCanvas = new Canvas(mBufferedBitmap);
        }

        paint.setColor(Color.BLUE);
        mBufferedCanvas.drawLine(0, getHeight(), getWidth(), getHeight(), paint);
        mBufferedCanvas.translate(0, -1);


    canvas.drawBitmap(mBufferedBitmap, 0, 0, null); 

    //draw fps
    mTextPaint.setColor(Color.WHITE);
    canvas.drawText(mFpsTracker.getFPSString(), 40, 40, mTextPaint);


    invalidate();       
}

【问题讨论】:

  • 如果有人对使用 SurfaceView 感兴趣,可以将此代码提高大约 10-15FPS
  • 我很纳闷,SurfaceView到底是什么东西可以神奇地提升性能?或者您可能以不同的方式使用 SurfaceView - 例如,我希望 RGB_565 在大多数设备上绘制速度更快。
  • 绘图是在 SurfaceView developer.android.com/reference/android/view/SurfaceView.html 的 UI 线程中完成的
  • 更正,允许在不同的线程上完成。 SurfaceView 不需要启动一个新线程。即使确实如此,引入新线程也不能自动保证给定任务的更好性能。
  • 你也在onDraw()内部调用invalidate()

标签: android graphics canvas bitmap


【解决方案1】:

请参阅 Romain Guy 的 this 博客文章。

提供视频版本here

不再使用 ARGB_4444。它已被弃用。每个像素每个通道仅分配 4 位(因此得名)。 ARBG_8888 提供 16,777,216 种颜色,而不是 ARBG_4444 的 4,096 种颜色,但每个像素使用 4 个字节而不是 2 个。

在 Gingerbread 中,Android 使 ARGB_8888 成为 Surface 的标准格式,并因此增加了每个进程的内存分配。

Window's 和(假设您使用流线型SurfaceView)SurfaceHolder 的格式设置为RGBA_8888 会更有效。这样可以避免明显变慢的格式更改。

其他提示包括:

  • 限制 Alpha 合成,因为这需要从 Skia 进行相对昂贵的混合。
  • 请求位图 Options 更喜欢 ARGB_8888 Config 并禁用抖动。
  • 如果可能,请删除窗口 background
  • 启用硬件加速,但请注意unsupported operations

在 2.1 设备上,我能够以 50 fps 在屏幕上绘制至少 300 个位图。

【讨论】:

  • +1 谢谢。你的位图和我上面的整个画布一样大吗?
  • 不,我将我的分解成可重复使用的部分,但就速度而言应该没有太大关系。一般来说,经验法则是您应该能够以 60 fps 的速度在屏幕上绘制 2.5 倍的像素数。
  • 当然,我想在不知道尺寸或设备的情况下很难量化性能差异 - 不过我很欣赏这篇文章和提示。你提到的经验法则来自哪里?
  • see here 虽然 60fps 的说法实际上来自 here,但由于文章中的事实错误和糟糕的写作,其案例并未得到充分证实。
【解决方案2】:

我遇到了和你一样的问题,当你发现一些新东西时请告诉我。

这是我迄今为止创立的:

  1. 对于 android 版本 > 3 最好不要使用双缓冲,因为您正在获得硬件加速(需要在清单中设置为 true)
  2. 设置paint.setDither(true) 它将在任何具有不同颜色的设备上运行得更好,然后是 ARGB_4444,大多数设备都是如此。 Check this out for more info

【讨论】:

  • 嘿,你确定将抖动设置为 true 会更快吗?文档说“没有抖动通常更快”
  • 我确定,在超过 7 台设备上进行测试。这没什么大的不同,但它有点帮助,而且图片看起来更好。检查我添加的答案中的链接
【解决方案3】:

在 onSizeChange 中,您可以根据画布大小调整大小或创建位图,然后帧绘制会快得多,大约 60fps,但是在无限循环中使用自定义视图会减慢某些速度,并且在某些 android 设备上会变得跳跃,因此我这样做了不推荐它。相反,最好使用 SurfaceView。

检查这个例子:How can I use the animation framework inside the canvas?

【讨论】:

  • +1 感谢您的链接。如果我开始使用错误大小的位图,在调用 onSizeChanged 之后,绘图肯定会更快吗?
  • 这只是因为android设备上的屏幕大小不同,加上honeycomb 3.x没有使用全屏,因为它在底部有一个面板,所以onSizeChanged告诉了画布的真实大小并且可以相应地调整其他图像,但与您正确的速度无关。
  • 在你的情况下,我不确定位图有多大,但一种快速的方法不是平移位图的画布,而是在不同的 X、Y 坐标上绘制位图,或者使用画布。 drawBitmap(bitmap, fromRect, toRect, paint) 和第二个例子中的移动矩形。
【解决方案4】:

你需要在某个地方创建你的位图(例如 onCreate 或其他地方(构造函数会很好)),因为当你做滚动效果时,你会一次又一次地创建新的位图。所以只需要在构造函数中创建而不是使用这个位图。

当我遇到类似问题时,这对我来说是一个很好的解决方案。 尝试在其他没有无效的地方创建这个mBufferedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);。 希望对你有帮助。

【讨论】:

  • 我在 ondraw() 调用中懒洋洋地加载我的位图,所以它只创建一次然后重用......我应该看看翻译,看看那里是否发生了什么奇怪的事情,或者也许在 ddms 下运行以查看是否有任何隐藏对象创建
【解决方案5】:

我认为你可以从画布中获得良好的性能..但这需要很多工作..

如果你从一个性能良好的图形库开始,那么即使你做错了很多事情,你可能仍然会以良好的性能结束:) 哈哈

有一场争夺最快绘图库的竞赛……libgdx 目前正在获胜……

http://code.google.com/p/libgdx/wiki/SimpleApp#Project_Setup

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 2013-11-06
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 2013-11-28
    相关资源
    最近更新 更多