我正在建立一个应用程序,我需要实时显示信号痕迹(想想你在医院心脏监视器上看到的那种)。为了使我的线条动画顺利显示,我希望帧速率大约为每秒15帧(我做了一些实验,得出结论这是最低的可接受帧速率)。它可能在这篇文章的上下文中无关紧要,但我可能在ListView中有很多这样的视图(每次显示约5个常见的约20个。)
到目前为止,我一直在使用自定义视图,扩展View类。我在包含片段中有一个线程,每隔~70ms重写一次视图就会调用视图上的invalidate()。这本身并没有引起问题,因为我已经优化了我的onDraw()函数,大部分时间都在2ms以内运行。
现在我已经在片段中添加了一个Spinner,在调试时我注意到,一旦我打开Spinner,适配器就会不断地调用getView()调用,即使我没有触及Spinner(即打开但不滚动)和还有点滞后。这让我意识到我的整个片段每隔约70毫秒被重绘一次,这对我来说听起来很糟糕。现在的问题是:
答案 0 :(得分:0)
我会尝试回答我的问题,以便对可能遇到同样问题的其他人有用。
在ListView中包含一堆SurfaceViews是一个失败。在我看来,由于SurfaceView绘图没有与UI的其余部分同步,滚动时会在视图之间闪烁黑色线条(这可能是因为SurfaceView通过getView()重新分配给新数据源并在显示之前显示有机会重绘自己)。显然,在getView()中触发重绘是不够的。
Delyan对我的问题的第一个评论是有效的,即使它可能并不总是适用。如果我手动浏览ListView中的每个视图并在其上调用invalidate(),则重绘不会在层次结构中冒泡(我不需要无效(l,t,r,b)签名,但它可能是智能的如果您遇到过度重绘问题,可以尝试一下。因此,尽管Romain Guy在他的演讲中提到无效()将冒泡到根,但显然并非总是如此。 Delyan关于HW / SW的不同实现的评论可能是原因 - 我在HW中呈现我的观点。
无论如何,要解决这个问题,我在我的适配器中创建了这个方法:
public void redrawTraces(ListView lv) {
final int viewCount = lv.getChildCount();
for(int i=0; i < viewCount; i++) {
final View stv = lv.getChildAt(i);
if(stv != null) {
stv.invalidate();
}
}
}
视图不是SurfaceViews。最后,为了弄清楚我做错了什么,我这样做了:
adapter.notifyDataSetChanged();
此调用确实冒出来并导致重写整个层次结构。我的假设是,这大致相当于在更新整个层次结构方面调用listView.invalidate();也许这是正确的我没有调查它。