I have a Service that sends out updates every few hundred milliseconds. I have a String that gets created each time with a description of the event ("Time elapsed is 32 seconds"). Unfortunately I can't just use ints because the content can change depending on the event (usually however it's the same event type) and the feedback is going back to the user. Is there a way I can statically reuse the same String so that there aren't 100s of String allocations per minute? Even if I reuse the same variable, ie:
mEventUpdate = "Time elapsed is " + time + " seconds";
I still see a lot of String allocations being made.
At least you can use String.format() to reduce the number of created objects:
mEventUpdate = String.format("Time elapsed is %d seconds", time);
A String in Java is an unmutable object. Once created, you cannot change it any more. So if it really has to be a String there is no way to avoid the allocations.
Use StringBuffer
If you have a method returning a string, and you know that its result
will always be appended to a StringBuffer anyway, change your
signature and implementation so that the function does the append
directly, instead of creating a short-lived temporary object.
http://developer.android.com/training/articles/perf-tips.html#ObjectCreation
I wont bother with a long answer, either use format like someone said or use the often-overlooked StringBuffer - which I use when joining large number of Strings together, say in a loop, where using format wouldn't be possible.
http://developer.android.com/reference/java/lang/StringBuffer.html
(I like Android's reference because look it compared to that nasty Oracle's nasty one :P)
Declare this as global static variable
public static StringBuilder mEventUpdate = new StringBuilder();
mEventUpdate.delete(0, buffer.length());
mEventUpdate.append("Time elapsed is ");
mEventUpdate.append(time);
mEventUpdate.append(" seconds");
// TO desplay
mEventUpdate.toString();
Related
Oddly I'm having the inverse problem to many similar posts; I'm trying to use JodaTime (on Android) to give me a dd:hh:mm:ss type output and failing miserably. Code is;
public String GetEventTimeString(boolean withMS, int eventTime)
{
Period p = new Period(eventTime, PeriodType.yearMonthDayTime());
if (withMS)
return _formatter_withms.print(p);
else return _formatter_withoutms.print(p);
}
When I use the debugger to halt after p is set, I see that p itself has the hours value set to 568 and the days value is zero, so I've not posted the code that creates the formatters. eventTime is an int representing elapsed time in ms and has a value of 2045489151 in this case.
In case there's some oddity with the size of the number and the fact it's an int instead of a long, I tried making a new Period(1500000L, PeriodType.yearMonthDayTime()) and got a period of 0 days, 25 hours, 0 minutes and seconds.
Exploring the structure of the iType member of the period, I see an array iTypes containing elements "years", "months" etc. I also see an array iIndices which appears to map types to elements in some other array. Most indices make sense, but the index corresponding to "Days" is -1. So it seems PeriodType.yearMonthDayTime() isn't doing what I think the docs say it should.
If I try PeriodType.yearWeekDayTime I get the same result. If I try PeriodType.yearWeekDay then the three fields are zero with my 25 hour test value. So it's not just the one PeriodType that's misbehaving.
Wondering about the coincidence of getting exactly 25 hours from my fairly arbitrary (picked a number and kept adding zeroes) 1500000ms, I tried 1510000 and got 25h 10m 0s. But neither of those actually makes any sense when you work the conversion manually!
This is on Android, up to date Android Studio 1.3.2, not sure how to tell what version JodaTime I'm using but it's within the last few months and this seems a bit too glaringly obvious to be an obscure bug- more a combination of misunderstanding and digging too deep on my part I think.
Does anyone have any thoughts on what's going on?
Well, Joda-Time says about the normalization of a millisecond-based period:
Creates a period from the given millisecond duration. Only precise
fields in the period type will be used. Imprecise fields will not be
populated.
Here the question arises: Is the day unit a precise field in context of Joda-Time? No because a day can have 23 or 25 hours when it comes to switching daylight-saving time on/off in many countries (in reality there are even more possibilities like 23.5 hours etc). So the constructor you call does not fill the day-unit-field.
How can you get the desired normalization effect? Just do this recommended approach (no normalization in constructing the period):
long eventTime = 2045489151;
Period p = new Period(eventTime, PeriodType.millis());
System.out.println(p); // PT2045489.151S (no normalization)
System.out.println(p.normalizedStandard(PeriodType.dayTime()));
// P23DT16H11M29.151S
System.out.println(p.normalizedStandard(PeriodType.yearMonthDayTime()));
// P23DT16H11M29.151S ( the same result as one line before, not the best period type)
It is for debate IMHO that the Period-constructor, you used does a partial normalization. In my opinion either a full normalization using the given period type or no normalization at all (preferred by me - just leaving the milliseconds as millis, but then the second constructor argument is simply silly) would have been a wiser design decision. Interestingly (and confusing, too), the constructor without explicit period type argument does a partial normalization, too. To avoid premature incomplete normalization in constructor, you have to explicitly specify the period type as PeriodType.millis(). Sorry for your confusion.
I FINALLY have the map and points(arrays) working for my app. Quick question: I have a fatal exception with substring(), a "stringIndexOutOfBoundException"
In general, what is that referring to?
An I going past the end of a string using substring()?
Thanks,
testing.substring(1,2);
(I want to parse each character to find specific characters)
I wouldn't use substring() for grabbing 1-length strings (which is just a single character), but rather charAt(int) for specific positions. If you need to go over all characters in the string, you're probably better off with by converting the whole thing to a char[] first (using toCharArray()) and iterate over that.
Yes, you're going past the end of your strings bounds generally.
The Java API even tells you so...
IndexOutOfBoundsException - if beginIndex is negative or larger than the length of this String object.
You should get used to using the API. It tells you what exceptions a method throws and why.
Try printing the Strings length and value before attempting substring. That'll help you see the problem.
For example...
String testing = "Hello StackOverflow";
System.out.println("Length of testing = " + testing.length);
System.out.println("Value of testing = " + testing);
testing.substring(1,2);
Like stated in the official doc here:
public String substring(int beginIndex)
Returns a new string that is a substring of this string. The substring begins with the character at the specified index and extends to the end of this string.
Throws: IndexOutOfBoundsException - if beginIndex is negative or
larger than the length of this String object.
Why does this code trigger a force close in Android?
`score.setText(Integer.parseInt((String) score.getText())+1);`
score is a TextView, and I am simply increasing the number by 1. I have predefined a String resource to be the initial number in the score TextView.
I am quite frustrated.
First off you should try breaking down your code so you can actually see what is going on with it.
Instead of
score.setText(Integer.parseInt((String) score.getText())+1);
try
String tmp = score.getText().toString();
int score;
score = Integer.parseInt(tmp) + 1;
score.setText(String.valueOf(score));
EDIT: Upon further reading of the documentation, setText has several overloads, one of which DOES take an int, but it takes the int of a resource ID. My guess is that your score is not a valid resource ID, thus crashing your application.
public final void setText (int resid)
Oh and as far as the frequent FC's when beginning Android Dev, it happens to the best of us. The key is to learn WHY the FC's happen, and have a LOT of patience.
mostly u need to do this
score.setText(Integer.parseInt(score.getText().toString())+1);
coz.. getText() returns a Editable Object which cannot be parsed to Integer. So it give NumberFormat Exception.
AndMake sure to set TextView,s Text to an integer initially..
try this way
score.setText(String.valueOf(Integer.parseInt(score.getText().toString())+1));
as you can pass the integer value that's why getting force the application
TextEdit.setText takes a CharSequence as input.
You are supplying an integer through Integer.parseInt((String) score.getText())+1
See, if converting it back to string and using it in setText helps.
You can convert an integer to string using Integer.toString.
PS: I am new to java myself.
The compiler should have ideally caught this error.
It's possible java uses some implicit type conversions from string to int.
I have a very basic TCP socket connection to a remote device that I can poll for status.
Aside from the socket programming, which I have mostly figured out through asynctask, I'm trying to come up with a way to parse out the returning string.
I query the device with something like "VOL?"
The device responds with the Volume of 12 different audio outputs with this:
"VOL:33,0,21,12,0,43,0,0,0,0,20,0"
The ":" character always and only comes back after the echo of the initial command, so I can use whatever comes before the colon to flag what sort of answer is coming in. (VOL, BAS, MUT, TRE, BAL, etc)
In the case of VOL, I simply want to chunk out everything that comes between the commas, so I can chop up and place into an array the volumes of all zones.
The only thing I can think of is to grab the length of the string, then run a for loop through it searching for commas one by one, but it seems ridiculously messy:
int oldPos = 0; //used in the upcoming 'if clause' to mark where the last comma was found
int y = 0; //used to old the resulting value's array position
String strIncoming; = //the incoming TCP string
for(int x = 0; x <= strIncoming.length(); x++){
if(",".equals(strIncoming[x]){
volzoneVal[y] = strIncoming.subString(oldPos,x);
oldPos = x;
y++;
}
}
there has GOT to be a better way, (and I'm not even sure this is going to work, I'm typing it here for the first time as I brainstorm this problem, so it's not been run or compiled)
Is there a better way to scan through a string looking for hits?
strIncoming.split(":")[0] will give you what was before first colon
strIncoming.split(":")[1].split(",") will give you array of individual strings
First, split the string on the colon, and then split[0] is your type. Then take split[1] and split it on the comma, and you'll have all your 12 different outputs ready to go (just convert them to integers).
Use Java's string split function and split on the comma as the delimiter. You will then have an array of your parameters. If you append some kind of "end string" character to each response, you will know the start and end based on the colon for the start and your end character for the end.
I'm a little confused about how to send data over a Bluetooth connection. In the Android API documentation, from the Bluetooth Chat example, the class BluetoothChat.java constructs a Handler object. Within there is a switch statement, and a MESSAGE_WRITE case. Do I need to implement similar code to send Strings over Bluetooth? A case statement for each String I want to send? In particular I want to send (name,value) pairs so I know what is sent and what it's value is. How do I implement this? If, following the example, I call BluetoothChatService.write(String.getBytes()) a bunch of times to send...? Then how would I know which strings are associated with which names? Please help.
I'm using Google's Protocol Buffers to send structured data over bluetooth connections in my Android app. protobuf takes care of figuring out how to serialize the message for you so that you only have to send a byte value (length of the message) and then the serialized message; the library takes care of unserializing the message on the other end and populating the fields of a custom object. Definitely take a look at it; it made the writing of a custom bluetooth socket protocol quite easy.
Serialize pairs to any of formats which allows byte representation. Such as XML or JSON. Or even your custom format, it wouldn't be difficult for pairs of strings. And then send it.
For simple pairs of strings (Such as names), you could simply use some character to define when the first string stops, and the next begins.
For example, I use a format such as this to send a set of 3 strings from one device to another:
String toSend = partOne + ":" + partTwo + ":" + partThree;
On the other device, to get the strings you sent, use the String.split() method like so:
String parts[] = received.split(":",3);
The 2nd parameter is a limit to how many times to split. In this example, there are 3 strings, so split 3 times max.
The downside to doing this is that you need to use characters that will never be in all but the last string.
In my application, I used this method to send data about text messages, and the first 2 parts are the phone number and timestamp, so there can never be a : in it. For names, a newline would probably work.
If your going to send more complex data, definitely use something like Protocol Buffers.