Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/200.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 在onDraw()中避免对象分配(StaticLayout)?_Android_Ondraw - Fatal编程技术网

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

Android 在onDraw()中避免对象分配(StaticLayout)?,android,ondraw,Android,Ondraw,我有一个自定义视图,我很快就学会了不在其中进行对象分配,并将所有绘制分配移动到另一个方法中,很好 我需要使用StaticLayout,但是对于一些应用了可扩展的“东西”的文本 layoutBpm = new StaticLayout(bpmValue, textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); layoutBpm.draw(canva

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

我需要使用StaticLayout,但是对于一些应用了可扩展的“东西”的文本

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

    layoutBpm.draw(canvas);
这对我来说似乎是有道理的,但我当然被警告要避免这样做。对我来说,尽我所能避免任何性能问题是很重要的,所以我正在努力正确地做到这一点

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

希望这是有意义的,我对这很陌生。谢谢你的帮助


(编辑:我假设将此赋值放在方法中并从onDraw/onMeasure调用是愚蠢的,会停止Eclipse警告我,但实际上没有帮助?

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

对于
静态布局
,您只需要在文本更改或调整填充、间距或最大宽度时创建新布局。如果文本经常改变,那么您可能需要考虑<代码>动态布局> /代码>,它将每次重新测量自身。重新测量要比创建新对象花费更多的开销,但它发生的频率不可能比
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);
}
基本上,只有在某些内容发生更改时才创建新布局。否则,只需重复使用上次创建的对象

编辑:

跳过测量过程的一种方法是对新调整大小的视图本身调用
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();
    }
基本上,这会告诉布局视图可以达到的最大值。它会测量自己和它的孩子。将在父级(自定义视图)上调用forceLayout(),该父级将根据新的测量值重新布局其他内容

我应该注意到,我从来没有用静态布局做过这件事,所以我不知道会发生什么。在创建视图时,似乎已经处理了这种类型的度量,但可能没有


我希望这有帮助

谢谢,这给了我一种稍微新的看待事物的方式。实现上述功能的唯一问题是
textPaint
依赖于已调用的
onMeasure()
(文本根据画布大小进行缩放),以及
textWidth
(确定文本何时换行),因此我无法执行
createLayout()
在构造函数中首次查看。我可以把它放在 OnMead()/<代码>中,我认为它不是经常调用的。文本实际上改变了很多,我正在研究的视图实际上是一个圆形的搜索条,中间的文本用于中间的文本,它与搜索条的进度有关。因此,当您将手指绕着圆圈拖动时,值会不断变化。我认为,虽然值变化很大,但长度始终填充为三位数,因此布局永远不需要调整大小,因此StaticLayout就可以了。我几乎找不到关于静态/动态布局的文档,所以我不确定这是否正确。再次感谢您的帮助。因此,最后(我想),我将
onMeasure()
替换为
onSizeChanged()
,因为我的布局需求很简单,并将对
createLayout()
的初始调用放在那里,而不是
onMeasure()
。出于某种原因,Lint似乎不介意在
onSizeChanged()
中分配对象,但不喜欢在
onMeasure()中分配对象。我想这两种方法被调用的次数是一样的,所以我不知道为什么其中一种方法是好的,而另一种方法是不好的,但不管怎样,这似乎是好的。我主要关心的是如何从我已经完成的
onDraw()
中获得分配。再次感谢。我很高兴你设法使一些东西起作用,但这里有一些注释。皮棉警告被编程为简单的常见错误。仅仅因为你没有得到警告并不意味着它是好的。另一方面,仅仅因为你得到了警告并不意味着它是坏的。这只不过是一个建议。onSizeChanged()实际上不会被调用太多,因为只有在onMeasure()中记录了不同的度量时才会调用它。另一方面,onMeasure会为树中的每个视图调用,甚至可能更多。无论大小是否改变。可以在不经过onMeasure()过程的情况下重新测量布局。基本上,对于新的测量,您在视图上调用
View#measure()
,视图本身将重新测量。但是,不同之处在于父视图中的其他元素将保持不变。如果出现问题,则需要调用布局过程来重新调整视图中的其他图元。我已经用我的意思更新了答案。