我正在使用自定义绘制视图实现ListView活动,并具有以下代码:
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
....
canvas.drawText(String.format("%02d: %dx%d", position, w, h),
10, 15, cached_paint);
}
在onDraw方法中几乎没有别的东西,所以这让我很生气,为什么滚动这么差。我偶然把drawText参数更改为不使用String.format,然后突然滚动了黄油丝。实际上,以下内容实际上相同但表现良好:
canvas.drawText("" + position + ": " + w + "x" + h,
10, 15, cached_paint);
我很惊讶。为什么后者比调用String.format更快?我希望对象连接产生更多的中间对象和一般的垃圾性能,但我发现完全相反。事实上,当使用String.format运行时,我从vm获得了大量的分配/释放消息。
那么为什么String.format显然可以更快(至少来自其他编程语言,其中对象创建是昂贵的)时这么慢?
答案 0 :(得分:6)
与+
的字符串连接不会生成大量中间对象;基本上是一个StringBuffer及其内部字符数组(如果容量不足,可能会重新分配)。哦,和字符串在连接时。
此外,对于+
,分析进入字符串的对象的数据类型的大部分工作都是在编译时完成的。使用String.format,这是在运行时完成的。最重要的是,传递给String.format的每个基本类型都需要自动生成,这会产生更多的对象。
答案 1 :(得分:4)
我惊呆了。
为什么?
为什么后者比调用String.format更快?
因为它是用Java编写的。 %02d: %dx%d
不是Java。必须每次都解析它,并且每次都执行规则。这些规则通过java.util.Formatter
以Java身份执行。
现在,String.format()
可以通过将其替换为本机代码(C / C ++)实现进行优化,但我认为varargs和JNI会变得混乱。
我希望对象连接生成更多的中间对象和一般的垃圾性能,但我发现完全相反。事实上,当使用String.format运行时,我从vm获得了大量的分配/释放消息。
那是因为String.format()
相当复杂并且是用Java实现的。
答案 2 :(得分:1)
要获得最佳性能,您可以从java.text
包创建格式化程序并对其进行缓存。
final static DecimalFormat myFormat = new DecimalFormat("###");
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
....
canvas.drawText(myFormat.format(w) + "x" + myFormat(h));
}
为了获得更好的性能,您可以使用更快的字符串连接。但这是一种不同的优化方式,也是这个问题的主题。