我是不是每次通话都会使整个屏幕无效



我是Android开发的新手,正在阅读Hello Android这本书。它使用了一个数独的例子,我所指的代码就在这里。

在触摸屏上,它调用select方法,该方法调用invalide两次。问题是,在invalidating上,onDraw方法是紧接着调用的吗?因此,在这种情况下,在我的选择方法中,它将进行

  1. 无效
  2. 调用Draw
  3. 做一些事情
  4. 使无效
  5. 调用Draw

是这样发生的吗?同时,整个屏幕会重新生成吗?所有的数字和提示等等,因为从书中作者说

在这个例子的早期版本中,我使整个无论何时移动光标,都会显示。因此,在每个键上按下,整个谜题必须重新绘制。这导致它滞后明显。切换代码以使最小的无效改变的矩形使它运行得更快。

他到底想说什么?

添加的信息

我在onDraw方法中添加了一些日志,一些在开始时添加,一些在for循环中添加。每当我触摸一个新的矩形时,所有的日志都会被调用。这是否意味着整个屏幕都在重新填充,因为onDraw中的所有代码都被重新执行了?

海怪

Q: 但是日志呢?当然,如果我的循环被执行,这意味着所有的canvas.draw也将被执行
A:是的,整个绘图将在您的样例代码中执行。在onDraw方法中,您必须自己优化渲染过程。

Q: 系统如何知道,哪段代码"只"会重新绘制脏区域
A:Canvas::getClipBounds会给你一个脏矩形,你应该在上面画一些东西。
onDraw中的for loop中,将脏矩形与你想要画的矩形进行比较。如果它们不相交,则执行continue

但是请记住,如果有几个区域设置为脏区域,则返回的rect将是所有脏区域的并集
请参阅下面的两个问题:
获取draw()中的脏区域
Android:使(脏)无效

希望这对你有帮助。

==========================

作者是对的。但这仍然可以优化。

调用invalidate(Rect)将自动为画布设置一个剪辑区域。(这就是canvas.getClipBounds()可以返回该区域的原因)
然后,在onDraw()期间,任何从剪辑区域引出的内容都将被忽略。它们不会出现在屏幕上,所以它确实减少了绘制时间
但是忽略它们仍然需要开销。因此,对于图形密集型应用程序,如果事先排除它们,onDraw()可能会得到更好的优化。

你可以在android的KeyboardView中找到一个优化onDraw()的好例子,它提供了android输入法的视图。http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/inputmethodservice/KeyboardView.java

这直接来自View文档:

通过遍历树并渲染与无效区域相交的每个视图来处理绘图。因为树是按顺序遍历的,这意味着父母将在孩子之前(即后面)绘制,而兄弟姐妹则按他们在树中出现的顺序绘制。如果您为视图设置了可绘制的背景,则视图会在调用回其onDraw()方法之前为您绘制它。

请注意,该框架不会绘制不在无效区域内的视图

据我所知,一旦你的视图第一次绘制出来,一棵树就会由父对象和子对象以及它们在屏幕上的位置组成。当您经过指定的区域以使其无效时,将检查该树中该区域中受影响的节点,并且只有这些节点才会被调用进行绘制。

现在我也不明白的是,在这个例子中,唯一的视图是PuzzleView。我不确定如何优化图形或单个视图。检查文本中是否对其进行了进一步讨论。

如果不是,那么我的理论是画布对象(矩形)也是上述树的一部分,并且只绘制这些部分,即指定区域中的矩形。

更重要的是,在使用区域无效与完全无效后,您是否看到了任何改进?

即使多次调用invalide,onDraw方法也只能调用一次。基本上,当视图无效时,onDraw会在RunLoop方法内部调用。这意味着,如果在将控制权交还给运行循环之前多次使视图无效,则视图将只重绘一次。请注意,如果您使视图的两个不同矩形无效,系统将在重新绘制视图之前尝试使这些矩形并集。

在代码中,您所说的无效是:

invalidate(selRect);

如果是,则他仅调用此选定矩形的onDrawselRect

只有invalidate();重新绘制孔屏幕。

希望能有所帮助。

在这个例子中,您应该注意到invalidate()调用有一个Rect作为参数。这意味着只有视图的这个区域变脏了,并且将被系统重新绘制。

调用invalidate()之后不会立即触发onDraw()方法。系统只会在他想要重新绘制视图的时候做出决定。

来自Android文档:

如果视图可见,则会调用onDraw(android.graphics.Canvas)在未来的某个时刻。

知道在select方法内部,这种情况可能会发生:1.使视图的一小部分无效2.做一些事情3.使视图的另一小部分无效4.视图的这两个部分正在重新绘制

希望能有所帮助。

如上述

在启用硬件加速的情况下,使用rect进行Invalidate不会改变画布剪辑边界。无论传递给Invalidate的rect是什么,都会重新绘制整个视图。

在API 21中,完全忽略给定的矩形,而使用内部计算的区域。public void invalidate(int l, int t, int r, int b);public void invalidate(Rect dirty);已标记为弃用!

我通过指定要绘制的位图的子集来解决这个问题。

class MyView extends View {
private Bitmap mBitmap;
private Rect mBound = new Rect(0, 0, 300, 300); // 300x300 by default, invoke updateBound if in needed

...

private void updateBound(PointF pointF) {
if (mBound.left > (int)pointF.x) {
mBound.left = (int)pointF.x;
}
if (mBound.bottom < (int)pointF.y) {
mBound.bottom = (int)pointF.y;
}
if (mBound.top > (int)pointF.y) {
mBound.top = (int)pointF.y;
}
if (mBound.right < (int)pointF.x) {
mBound.right = (int)pointF.x;
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
...
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, mBound, mBound, null);
}
}

默认情况下,我只在(0,0300300)的区域中绘制。但如果需要,您可以更新绑定,只需调用updateBound即可。

相关内容

最新更新