ANDROID如何减少字符串分配

ANDROID如何减少字符串分配,android,Android,我已经设法使用DDMS(很棒的工具)将我的分配降低到几乎为零,这使我的GCs大幅降低到大约每3分钟1或2次。尽管如此,我还是不高兴,因为当你与游戏互动时,这些通常会导致游戏(在某些手机上)明显延迟 使用DDMS,我知道分配是什么,它们是从用于向HUD显示游戏信息的整数转换而来的字符串 我基本上是这样做的: int playerScore = 20929; String playerScoreText = Integer.toString(playerScore); canvas.drawText

我已经设法使用DDMS(很棒的工具)将我的分配降低到几乎为零,这使我的GCs大幅降低到大约每3分钟1或2次。尽管如此,我还是不高兴,因为当你与游戏互动时,这些通常会导致游戏(在某些手机上)明显延迟

使用DDMS,我知道分配是什么,它们是从用于向HUD显示游戏信息的整数转换而来的字符串

我基本上是这样做的:

int playerScore = 20929;
String playerScoreText = Integer.toString(playerScore);
canvas.drawText(playerScoreText, xPos, yPos);
int score = 324;
char firstPlace = charMap[score%10];
char tenslace = charMap[(score/10)%10];
char hundredsPlace = charMap[(score/100)%10];
每次帧更新时都会发生这种情况,HUD系统是模块化的,所以我需要时会插入一些东西,这会导致4或5个HUD元素在DDMS中分配字符串和AbstractStringBuilder

有没有办法进一步减少这些或消除所有字符串分配,只需重用字符串对象

谢谢,
阿尔伯特·普契亚尼(Albert Pucciani)

读到你的问题让我想起了罗伯特·格林(Robert Greens)的一篇文章,我很久以前读过这篇文章。它几乎以相同的方式讨论你的问题。跳到第33天开始阅读。

记住最后一个整数分数及其字符串表示形式。在新帧上检查分数是否相同。如果相同,则无需创建新字符串-只需使用旧字符串。

以下是我过去所做的。这将消除字符串分配

我创建了一个字符[],其大小至少与您需要在屏幕上显示的最大字符数相同。这意味着您应该选择在游戏中可以达到的最高分数。你现在的方式让你展示一个高达2^31-1的分数,这是非常巨大的,这对于游戏来说是不现实的。请记住,这是您的游戏,因此,在游戏环境中,可以将最大分数限制在更合理的范围内。选择一个几乎不可能实现的数字。设置此限制将使您不必费力地将大整数转换为字符串对象

以下是所需内容:

首先,您需要能够在不创建字符串对象的情况下分离整数中的数字并将其转换为字符。假设您希望将324的整数转换为三个单独的字符“3”、“2”和“4”,以放置在文本char[]中。你可以这样做的一种方法是取324的值,然后做一个mod 10来得到最低的数字。所以324%10=4。然后将该值除以10,再进行一次模10运算,得到下一个数字。所以(324/10)%10=2和(324/100)%10=3

您必须在循环中执行上述操作,但这表达了您在这里尝试执行的想法

接下来,使用这些数字,您可以通过引用字符映射将它们转换为字符。一种方法是创建这个角色映射,方法是创建一个大小为10的char[],并将值0-9放在索引0-9中

char[] charMap = {'0','1','2','3','4','5','6','7','8','9',};
这样做:

int playerScore = 20929;
String playerScoreText = Integer.toString(playerScore);
canvas.drawText(playerScoreText, xPos, yPos);
int score = 324;
char firstPlace = charMap[score%10];
char tenslace = charMap[(score/10)%10];
char hundredsPlace = charMap[(score/100)%10];
将为分数中的3位数创建所需的字符

现在,在所有这些之后,我将最高分数限制在99999分(或者在游戏中有意义的任何分数)。这意味着我需要显示的最大“字符串”是“Score:xx,xxx”。这将需要大小为13的char[](本例称之为text)。用“Score:”初始化前7个字符,这些字符永远不需要更改

char[] text = new char[13];
text[0] = 'S';
text[1] = 'c';
text[2] = 'o';
text[3] = 'r';
text[4] = 'e';
text[5] = ':';
text[6] = ' ';
接下来的6项将根据分数而有所不同。请注意,您可能不需要填写所有剩余的6个字符,因此您需要创建一个int(在本例中称为scoreCount),它将告诉您文本char[]中有多少字符与游戏中的当前分数实际相关。假设我需要显示“Score:324”,这只需要13个字符中的10个字符。将得分为324的3个字符写入字符[7]到字符[9],并将scoreCount设置为10,以指示字符[]中的有效字符数

int scoreCount = 7;
text[9] = charMap[score%10]; // This is firstPlace
text[8] = charMap[(score/10)%10]; // This is tensPlace
text[7] = charMap[(score/100)%10]; // This is hundredsPlace
scoreCount = 10;
您可能需要在一个循环中执行上述操作,但这应该表达您在这里尝试执行的总体想法

之后,您可以只使用drawText(char[]text,int index,int count,float x,float y,Paint Paint)索引将为0,计数将为计分计数,指示文本中应绘制的字符数。在上面的例子中,文本[10]到文本[12]中的内容并不重要,它被认为是无效的。您可以继续使用角色映射更新文本[],这不应创建任何对象


我希望这有帮助。上面的代码不是很健壮,但我写出来更多的是表达我试图表达的想法。您必须创建自己的循环并在代码中正确管理数据,但这总结了避免使用Strings/StringBuilder/StringBuffer/等所需的机制。

如果GC导致延迟,听起来您好像做错了什么。将整数转换为字符串是一个极其简单的操作,您对此无能为力,因为它最终必须在某个地方转换为字符串。请改为使用它-请参阅@tp0w3rn answer。@Falmari:问题不在于分配:1个字符串分配x 5个HUD元素x每秒40次x 10秒=等于剩余的大量垃圾@彼得·克内戈:谢谢,直到我重新阅读你的文章,我才注意到底部的tp0w3rn的答案。嗨,我考虑过这一点,但考虑到HUD元素经常变化,可能是每秒4-5次(如计时器、条纹、分数变化等),它们的字符串分配量仍然很大当我启用调试控制台时,情况会更糟,因为我使用了大量字符串。太棒了,工作得很好,再次感谢!我会投票支持你,但我没有足够的声誉。你仍然可以接受我的正确答案:)。很高兴我能帮忙,我也是新来的。