从View#draw调用ViewGroup#addView或ViewGroup#removeView

时间:2014-02-18 19:35:55

标签: android android-canvas android-view

Android documentation中,它为addView(以及其他一些方法)说明了以下内容:

  

注意:不要从draw(android.graphics.Canvas)调用此方法,   onDraw(android.graphics.Canvas),dispatchDraw(android.graphics.Canvas)   或任何相关的方法。

这种限制的原因是什么?另外,“相关方法”是什么?例如,surfaceChanged这样的方法是什么?

1 个答案:

答案 0 :(得分:2)

这是因为在渲染View时,包含ViewGroup的{​​{1}}在映射每个视图将出现在屏幕上的位置时会经历某些步骤。 View采取的步骤是:

  1. 衡量(ViewGroup衡量其所有子视图)
  2. 布局(ViewGroup根据测量结果将测量的孩子定位在屏幕上的位置ViewGroup
  3. 绘制(视图在屏幕上绘制)。
  4. 由于绘制步骤是在屏幕上呈现ViewGroup.LayoutParams时的最后一步,因此在此过程的这一步添加额外的View可能会改变(使无效)整个布局。如果您查看View的源代码,您会看到拨打ViewGroup会再次启动整个布局过程:

    addView(View v)

    此外,当public void addView(View child, int index, LayoutParams params) { if (DBG) { System.out.println(this + " addView"); } // addViewInner() will call child.requestLayout() when setting the new LayoutParams // therefore, we call requestLayout() on ourselves before, so that the child's request // will be blocked at our level requestLayout(); invalidate(true); addViewInner(child, index, params, false); } 在屏幕上绘制其子ViewGroup时,它通常会遍历当前添加到View的所有View。因此,如果在绘制方法期间调度此类事件,则可能导致ViewGroup尝试绘制尚未完成渲染所需步骤的ViewGroup

    至于相关方法,这些方法基本上是使View当前绘图操作失效的方法。

    编辑:

    SurfaceHolder.Callback方法只是用于跟踪绘图表面状态的ViewGroup方法,或SurfaceView / GLSurfaceView。由于布局的状态应该保持不变,直到Draw步骤完成,因此在该过程中的那一点上不应该真正需要调用此方法。但是,由于这些方法基本上都是你实现的接口方法(默认情况下它们在源代码中是空的),因此调用其中一种方法应该导致错误的原因应该不是真的,即使我不确定这样做是合适的。如果您的基础实施导致像我上面解释的那样的问题,那么可能会出现问题的一个案例就是......