我正在制作一个带滚动背景的动态壁纸。我有两个位图对象,我之间交替,以保持下一帧的先前绘制的像素。我在画布顶部绘制一个新行,然后调用drawBitmap将其余像素复制到画布上。
我正在使用Runnable对象来完成繁重的工作。它执行所需的所有复制和计算,然后锁定画布,在持有者上输入同步块,并对Canvas.drawBitmap(位图,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);
}
}
在Runnable的draw()
中调用run()
函数。
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()
函数是我如何保持我绘制的先前像素。被称为源的Rect是底部大小不足全屏的一行,其中目标是顶部的一行短。 <{1}}中的drawBitmap()
次呼叫永远不会超过2-4毫秒。
prepareFrame()
这个单一操作是在持有锁的情况下在画布上完成的。
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);
}
的各种签名,但只发现它们平均较慢,但仍会导致异常的白色闪烁。
我的整体速度很棒。没有间歇性闪光,它的效果非常好。有人有关于如何消除闪光的建议吗?
答案 0 :(得分:5)
很难确切地知道这里发生了什么,因为你没有包括定义或使用一些中心变量,如“mainCan”或“ca”。更完整的源参考将是伟大的。
但是...
可能发生的事情是,因为drawFrame(canvas)在holder上同步,但是
handler.post(drawRunner);
不是,当你在prepareFrame()中写入mainBmp的同时,你会尝试将mainBmp绘制到系统画布。
这个问题的最佳解决方案可能是某种双重缓冲,你可以在其中执行类似
的操作1) Write to a temporary bitmap
2) Change the ref of that bitmap to the double buffer i.e. mainBmp = tempBitmap;
主要目标是永远不要对用于系统画布渲染的变量进行长时间写入,只需更改对象引用即可。
希望这有帮助。