【问题标题】:Low framerate writing bitmaps to the canvas低帧率将位图写入画布
【发布时间】:2013-08-17 04:50:28
【问题描述】:

我有一个动态壁纸,它通过将每一帧绘制到画布上来运行循环动画。我有一张图片,大小与屏幕的确切尺寸一致。我有一组 400 个帧,大小正好适合屏幕底部三分之一;这是动画发生的地方。以下是显示它们的代码:

public void updateBG() {
    mHandler.removeCallbacks(mUpdateDisplay);
    if (mVisible) {
        mHandler.postDelayed(mUpdateDisplay, 40);
    }

    if (imagesLoaded < totalFrames) {
        ShowLoadingProgress();
    } else {
        SurfaceHolder holder = getSurfaceHolder();
        Canvas c = null;
        try {
            c = holder.lockCanvas();
            if (c != null) {
                Paint p = new Paint();
                p.setAntiAlias(true);
                c.drawRect(0, 0, c.getWidth(), c.getHeight(), p);
                Rect destinationRect = new Rect();
                destinationRect.set(0, 0, canvasWidth, canvasHeight);


                if (animStartX > 0 || animEndX > 0 || animStartY > 0 || animEndY > 0) {
                    c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[totalFrames], 0, bitmapArray[totalFrames].length), null, destinationRect, p);
                    Rect destinationRectAnim = new Rect();
                    destinationRectAnim.set(animX, animY, animX+animWidth, animY+animHeight);
                    c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[bgcycle], 0, bitmapArray[bgcycle].length), null, destinationRectAnim, p);
                } else {
                    c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[bgcycle], 0, bitmapArray[bgcycle].length), null, destinationRect, p);
                }

            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
        bgcycle++;
    }
}

此代码在 Xperia Ion(双核 1.5 GHz cpu)上以大约 10-12 FPS 的速度运行,在旧设备上运行速度更慢。当我以屏幕分辨率的一半保存整个帧时,情况会好得多。当我开始以屏幕分辨率使用全帧时,它实际上变得更糟了(这应该消除了在每一帧上进行插值的需要)。当我开始使用这段代码时,情况变得更糟了,它写入了两个位图(大概是因为它无法保存上次运行的画布的上半部分)。

我该如何优化呢?我宁愿不保存完整的帧,因为只保存每一帧的动画部分确实可以减少内存使用量。这里感觉有些不对劲,特别是考虑到它背后有 3GHz 的功率运行。我曾经在 450 MHz Pentium III 上看电影。有什么明显的我做错了吗?即使尺寸正确,手机是否仍在尝试插入图像?

【问题讨论】:

  • 最后,在用AndEngine尝试了一个类似的应用程序后,我决定逐帧的方法不适用于显示视频。相反,我决定转向 FFMpeg,并希望将其提高到合理的帧速率。

标签: java android


【解决方案1】:

您正在解码每一帧的位图,这很昂贵,并且会产生触发 GC 的垃圾。您还使用软件渲染进行渲染。以下是您的解决方案,按顺序排列:

  • 不要重新解码每一帧的位图
  • 重用位图对象(请参阅 BitmapFactory.Options.inBitmap)
  • 使用硬件加速(直接渲染到 View 而不是 SurfaceView。)软件插值非常昂贵。

【讨论】:

  • 我必须研究所有这些;我在 Java/Android 开发方面仍然很年轻。你能告诉我“不要在每一帧上重新解码”是什么意思吗?我将图像存储在一个字节数组中作为 JPEG,这避免了每帧上的 io,但如果我将它们存储为 bmps,我会吃光数百 MB 内存。我是不是误会了?谢谢!
  • 另外,如果可能的话,尽量不要在循环中重新创建像 PaintRect 这样的对象。如果性能完全是一个问题,我会认真考虑将位图保存在内存中。位图解码绝对是一个很大的因素。
  • 您能否指导我看一些解释这些的代码示例或教程,尤其是 view 和 surfaceView 之间的区别?谷歌只向我指出 SO 答案,这些答案通常非常直接且适用于更有经验的开发人员。我的书讨论了活动中的图形渲染,我知道这与动态壁纸有一些重要的区别。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 2016-03-17
相关资源
最近更新 更多