在onDraw()(StaticLayout)中避免对象分配?

时间:2013-06-13 17:00:19

标签: android ondraw

我有一个自定义视图,我很快学会了不进行对象分配,并将所有Paint分配移动到另一个方法中,很好。

我需要使用StaticLayout,但是对于某些应用了某些spannable'stuff'的文本。

    layoutBpm = new StaticLayout(bpmValue,
            textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1,
            false);

    layoutBpm.draw(canvas);

这对我来说似乎对onDraw很有意义,但我当然会收到警告以避免这种情况。对我来说,尽我所能避免任何性能问题对我来说很重要,所以我正在努力做到这一点。

我似乎无法找到任何我能理解的文档,它解释了StaticLayout实际上做了哪些参数(float spacingmult?float spacingadd?),但我认为第三个是StaticLayout文本的最大宽度我只能从onMeasure获得,因为它与我的画布大小有关。这让我想把作业放在onMeasure或onDraw上,这似乎都不是我想做的。是否可以在onDraw中放置StaticLayout赋值,或者有更好的方法吗?

希望这是有道理的,我对此非常陌生。感谢您的任何帮助。

(编辑:我假设将这个赋值放在一个方法中并且从onDraw / onMeasure调用只是愚蠢而且会阻止Eclipse警告我但实际上不会有帮助吗?)

1 个答案:

答案 0 :(得分:5)

警告的原因是,通常,您不需要在绘制操作中多次重新创建对象。与onDraw()中的其他方法相比,View可以被调用数百次。大多数情况下,正在使用精确参数重新创建正在重新创建的对象。其他时候,改变对象状态的开销比创建新对象的开销要少。

对于StaticLayout,您只需在文本更改或调整填充,间距或最大宽度时创建新的。如果文本经常更改,那么您可能需要考虑每次都会重新测量的DynamicLayout。重新计算成本比创建新对象的成本更高,但是它不会比onDraw()调用更频繁地发生。

如果文本没有经常更改,并且您绝对必须使用StaticLayout,那么您可以使用类似这种结构的东西。

StaticLayout myLayout;
String textSource = defaultSource;
Paint textPaint = defaultPaint;
int textWidth = defaultWidth; 

public CustomView(Context ctx) {
    super(ctx);
    createLayout();
}

public void setText(String text) {
   textSource = text;
   createLayout();
}

public void setWidth(int width) {
   textWidth = width;
   createLayout();
}

@Override
public void onDraw(Canvas canvas) {
   myLayout.draw(canvas);
}

private void createLayout() {
   myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false);
}

基本上,只有在发生变化时才会创建新的布局。否则,您只需重复使用您创建的最后一个对象。

EDIT:

跳过度量传递的一种方法是在新调整大小的视图本身上调用View#measure。所以你的createLayout()方法会是这样的。

   private void createLayout() {
       myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false);
       int textWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth, MeasureSpec.AT_MOST);
       int textHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST);
       myLayout.measure(textWidthSpec, textHeightSpec);
       forceLayout();
    }

基本上它的作用是告诉布局View的最大值。它将衡量自己和它的孩子。将在父(您的自定义视图)上调用forceLayout(),它将根据新测量值重新布局其他内容。

我应该注意到我从未使用StaticLayout做过这个,所以我不知道会发生什么。看起来这种类型的测量可能已经在创建视图时处理,但可能没有。

我希望这会有所帮助。