【发布时间】:2014-05-27 15:52:49
【问题描述】:
通过 ACRA,我收到了少量来自 alpha 版本软件的报告,这些报告表明在特定调用 Canvas.restore() 期间发生了异常。例外是java.lang.IllegalStateException: Underflow in restore。
我很清楚,如果restore() 调用次数多于save() 调用次数,就会发生此异常。但是,通过非常仔细的代码检查,我绝对可以肯定对 canvas.save() 和 canvas.restore() 的所有调用都是平衡的。也就是说,所有对canvas.save() 的调用肯定会在稍后阶段通过调用canvas.restore() 来平衡。我还可以确认,不存在可能导致缺少 canvas.save() 导致堆栈下溢的方法的条件、异常或提前返回。
此外,此问题似乎是一种罕见的极端情况,它会导致在每秒渲染多次的图形代码中仅发生几次异常。
发生这种情况的代码结构是:
protected void onDraw(Canvas canvas) {
...
someMethod(canvas);
...
}
void someMethod(Canvas canvas)
{
....
canvas.save();
....
someOtherMethod(Canvas canvas);
....
canvas.restore();
....
}
void someOtherMethod(Canvas canvas)
{
....
canvas.save();
....
for ( ... ) {
....
canvas.save();
...
canvas.restore();
...
}
....
canvas.restore(); // *** exception here ***
....
}
有些地方在循环中使用了save() / restore(),但调用又是平衡的。
报告来自运行 4.3 和 4.4.2 的设备。
我试图用谷歌搜索这个问题,我能找到的唯一有趣的 QA 是来自 clearly had unbalanced save() / restore() calls in his code 的人;这绝对不是我的问题。
这发生在自定义 View 子类的 onDraw(Canvas canvas) 方法的调用堆栈中,所有这些都发生在 UI 线程上。我没有接触过该Canvas 对象的其他线程。
在调用负责异常的特定 restore() 之前,我可能会通过调用 getSaveCount() 来检查堆栈,但这实际上只是在问题上粘贴了 Elastoplast。我宁愿了解导致下溢的边缘情况到底是什么,但这让我感到困惑。
是否有任何已知问题?当 UI 线程在 View 的 onDraw() 调用的上下文中时,任何类型的系统配置更改是否可能影响此 Canvas? Canvas 堆栈大小是否有任何已知限制?是否存在已知滥用画布堆栈的任何操作系统图形调用?
【问题讨论】:
-
你使用 saveLayer 吗?
-
我不使用 saveLayer。
-
我会使用某种 CanvasWrapper 来追踪它
-
虽然较旧的 Android 变得不那么实际,但该问题现在似乎再次出现在 Android 11 中。
标签: android android-canvas underflow