12

我正在制作带有滚动背景的动态壁纸。我有两个交替使用的位图对象,以便为下一帧保留先前绘制的像素。我在画布顶部画了一条新线,然后调用 drawBitmap 将其余像素复制到画布上。

我正在使用 Runnable 对象来完成繁重的工作。它完成所有需要的复制和计算,然后锁定画布,进入持有者上的同步块,并对 Canvas.drawBitmap(bitmap,rect,rect,paint) 进行一次调用。屏幕上偶尔会出现白色闪烁,这似乎与高 CPU 活动有关。在使用 traceview 时,我发现 drawBitmap 操作,特别是 Canvas.native_drawBitmap(),花费的时间比正常情况要长得多。通常它在 2-4 毫秒内完成,但是当我看到白色闪光时,它可能需要 10 到 100 毫秒。

private void draw() {
    SurfaceHolder holder = getSurfaceHolder();

    Canvas canvas = null;
    prepareFrame();
    try {
        canvas = holder.lockCanvas();
        synchronized (holder) {
            if (canvas != null) {
                drawFrame(canvas);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (canvas != null)
            holder.unlockCanvasAndPost(canvas);
    }
    afterDrawFrame();
    handler.removeCallbacks(drawRunner);
    if (visible) {
        handler.post(drawRunner);
    }
}

draw()函数在run()Runnable 中调用。

private void prepareFrame() {
    num++;
    if (num%2 == 0) {
        mainBmp = mainBmp1;
        mainCan.setBitmap(mainBmp1);
        mainCan.drawBitmap(mainBmp2, source, destination, null);
    } else {
        mainBmp = mainBmp2;
        mainCan.setBitmap(mainBmp2);
        mainCan.drawBitmap(mainBmp1, source, destination, null);
    }
}

prepareFrame()函数是我如何保持以前绘制的像素的方式。名为 source 的 Rect 在底部比全屏尺寸少一排,而目标在顶部少一排。drawBitmap()呼入prepareFrame()永远不会超过 2-4 毫秒。

private void drawFrame(Canvas can) {
    can.drawBitmap(mainBmp, source, destination,null);
}

这个单一的操作是在持有锁的同时在画布上完成的。

private void afterDrawFrame() {
    ca.calcNextRow();
    mainBmp.setPixels(ca.getRow(), 0, canWidth, 0, 0, canWidth, 1);
}

然后下一行新的像素被绘制到内存中的一个位图上。

我尝试过使用 的各种签名,drawBitmap()但发现它们平均速度较慢,并且仍然导致异常的白色闪烁。

我的整体速度很棒。没有间歇性闪烁,它工作得非常好。有没有人有关于如何消除闪光的建议?

4

1 回答 1

5

很难确切地知道这里发生了什么,因为你没有包括一些中心变量的定义或使用,比如“mainCan”或“ca”。更完整的源参考会很棒。

但...

可能发生的情况是,由于 drawFrame(canvas) 在持有人上同步,但是

handler.post(drawRunner);

不是,您会尝试将 mainBmp 绘制到系统画布上,同时在 prepareFrame() 中写入它。

这个问题的最佳解决方案可能是某种双缓冲,您可以在其中执行类似的操作

1) Write to a temporary bitmap
2) Change the ref of that bitmap to the double buffer i.e. mainBmp = tempBitmap;

主要目标是永远不要对用于系统画布渲染的变量进行长时间写入,只需更改对象引用即可。

希望这可以帮助。

于 2012-09-25T09:18:17.823 回答