If you don't need thread synchronization, use StringBuilder instead of StringBuffer.
R/ On Mon, May 25, 2009 at 3:47 PM, Robert Green <rbgrn....@gmail.com> wrote: > > The score changes every frame. I like how it works because it's tons > of tiny increments. I actually just did the thing I talked about with > the reusable char[]. The only caveat is that I have to allocate a new > one when the length of the string changes, but that only happens when > the score has changed by a factor of 10 and I don't see scores going > over 6 digits long. I suppose it's possible someone could play the > game forever and score much higher but it's highly unlikely. > > This is about as efficient as I will ever care to make such a thing. > If you want to _never_ allocate, you could make a char[][] where the > first dimension is the length of the second dimension arrays. That > would be char[1], char[2], char[3], char[4] and so on. That would > make it so that if your string size were 5 chars, you would say char[] > correctArray = myArrays[5]. I didn't both with that because a few > allocations are ok, just not one every tick of the loop. > > This is ugly but if you need something like this, it does work: > > I have a class called Util and I put this in it: > > private final static int[] intSizeTable = { 9, 99, 999, 9999, 99999, > 999999, 9999999, 99999999, 999999999, > Integer.MAX_VALUE }; > > private final static char[] DigitTens = { '0', '0', '0', '0', '0', > '0', '0', '0', '0', '0', '1', '1', '1', '1', > '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', > '2', '2', > '2', '2', '2', '3', '3', '3', '3', '3', > '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', > '4', '4', > '4', '4', '5', '5', '5', '5', '5', '5', > '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', > '6', '6', > '6', '7', '7', '7', '7', '7', '7', '7', > '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', > '8', '8', > '9', '9', '9', '9', '9', '9', '9', '9', > '9', '9', }; > > private final static char[] DigitOnes = { '0', '1', '2', '3', '4', > '5', '6', '7', '8', '9', '0', '1', '2', '3', > '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', > '5', '6', > '7', '8', '9', '0', '1', '2', '3', '4', > '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', > '6', '7', > '8', '9', '0', '1', '2', '3', '4', '5', > '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', > '7', '8', > '9', '0', '1', '2', '3', '4', '5', '6', > '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', > '8', '9', > '0', '1', '2', '3', '4', '5', '6', '7', > '8', '9', }; > > private final static char[] digits = { '0', '1', '2', '3', '4', '5', > '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', > 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', > 'q', 'r', > 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; > > // Requires positive x > private static int stringSize(int x) { > for (int i = 0;; i++) { > if (x <= intSizeTable[i]) { > return i + 1; > } > } > } > > public static void getChars(int i, int index, char[] buf) { > if (i == Integer.MIN_VALUE) { > System.arraycopy("-2147483648".toCharArray(), 0, buf, > 0, > buf.length); > } > int q, r; > int charPos = index; > char sign = 0; > > if (i < 0) { > sign = '-'; > i = -i; > } > > // Generate two digits per iteration > while (i >= 65536) { > q = i / 100; > // really: r = i - (q * 100); > r = i - ((q << 6) + (q << 5) + (q << 2)); > i = q; > buf[--charPos] = DigitOnes[r]; > buf[--charPos] = DigitTens[r]; > } > > // Fall thru to fast mode for smaller numbers > // assert(i <= 65536, i); > for (;;) { > q = (i * 52429) >>> (16 + 3); > r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... > buf[--charPos] = digits[r]; > i = q; > if (i == 0) > break; > } > if (sign != 0) { > buf[--charPos] = sign; > } > } > > > Then in my game code it looks like this (for my FPS counter): > > int fps = this.fps; > int fpsStringLength = Util.getSize(fps); > if (fpsChars.length != fpsStringLength) { > // re-allocate > fpsChars = new char[fpsStringLength]; > } > char[] fpsChars = this.fpsChars; > //copy the chars into the array > Util.getChars(fps, fpsStringLength, fpsChars); > StringBuffer fpsText = this.fpsText; > fpsText.delete(0, fpsText.length()); > fpsText.append(fpsChars).append(FPS_TEXT); > canvas.drawText(fpsText, 0, fpsText.length(), > worldWidth - 60, > worldHeight + INFO_HEADER_HEIGHT - 20, > gameResources.fpsPaint); > > > That is SO MUCH more code than I ever wanted there but it's > ridiculously more efficient than it was before so I'm going to call it > good and move on. > > Thanks for the help everyone! > > On May 25, 5:19 pm, Jason Proctor <ja...@particularplace.com> wrote: >> i'll suggest this again :-) >> >> when the score changes, convert to a string then, save it away, and >> draw that each frame. at least then, you're only doing an allocation >> when it changes. >> >> good enough? >> >> >> >> >My new method doesn't have problems with concatenating but no solution >> >so far has gotten around converting an integer into a String or >> >CharSequence. Any time you put an integer where a String should be, >> >java automatically uses Integer.toString(i) to build a String out of >> >it which allocates a char[] and also makes a new String. >> >> >So, besides ripping out stringSize and getChars from integer and >> >holding my own char[] for the converted int, is there a clean way to >> >handle that without new allocations? >> >> >On May 25, 4:29 pm, Jason Proctor <ja...@particularplace.com> wrote: >> >> i think Mark is saying that you could redraw the score separately >> >> from the label, potentially saving an implicit new StringBuffer >> >> (stuff).toString () ? >> >> >> if score is a number, then it will need to make a new String anyway. >> >> but you could cache the string of the score until the score changes, >> >> so that drawing the score becomes drawing to strings as opposed to >> >> going through StringBuffer. >> >> >> hth >> >> >> >It's a surface view so the whole scene must be rendered every frame. >> >> >I could put it on the background I suppose but it's simple enough to >> >> >just redraw the text. >> >> >> >On May 25, 4:10 pm, Mark Murphy <mmur...@commonsware.com> wrote: >> >> >> Robert Green wrote: >> >> >> > I said StringBuffer but I meant "Implied" StringBuffer, you know: >> >> >> >> > canvas.drawText(score + POINTS_LABEL, x, y, paint); >> >> >> >> Why redraw POINTS_LABEL every time? Can't you rework your scoreboard >> >> to >> >> >> only draw that once? >> >> >> >> -- >> >> >> Mark Murphy (a Commons >> >> >>Guy)http://commonsware.com|http://twitter.com/commonsguy >> >> >> >> Android App Developer Training:http://commonsware.com/training.html >> >> >> -- >> >> jason.software.particle >> >> -- >> jason.software.particle > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en -~----------~----~----~----~------~----~------~--~---