Kotlin .toInt() returns ASCII value - android

I'm working on a 3 track step sequencer, and the spinners for sample selection are causing me some trouble. The following code is executed when a saved pattern is loaded to set the correct samples.
for ((index, j) in spinners.withIndex()){
val item = loadingPattern[(48+index)]
Log.i("item", item.toString())
Log.i("int", item.toInt().toString)
j.setSelection(item.toInt())
}
The array "spinners" contains 3 spinners with 5 entries each. "loadingPattern" is a string that contains the pattern information. The last three characters are integers corresponding to the spinner position. When the spinner selections are as the following:
Spinner 1: Selected item index 0
Spinner 2: Selected item index 3
Spinner 3: Selected item index 4
The log "item" prints exactly these values. The log "int" however prints 48+index, so in this case 48, 50, 52. Since the toInt() function is also called on the value parsed to the .setSelection() function, this exception is triggered:
java.lang.ArrayIndexOutOfBoundsException: length=2; index=48
If anyone has an idea why this is happening, I would be very happy to know. Thank you all so much! I love this communtiy!
edit:
If the pattern is programmed like this:
typical pattern
The "patternString" is the following:
101010101010101010000000100000001000100010001000420
active steps are represented by 1, the others by 0. The last 3 digits are the spinner positions. Maybe this will help :)
Edit 2:
I just found this question: I have String with numbers when getting the char from string it shows '0'48 in kotlin. How to get the char alone in kotlin
And there they say that the ASCII value of 0 is 48. This means that toInt() probably returns the ASCII value of 0. But why is that and how can I get just the normal integer?

I found it out!
As stated in this article, the toInt() function only works for strings and indeed returns the ASCII value of chars. The correct way of doing this is using Character.getNumericValue().

Related

Kotlin chunked and map

I am quite new to all things Android and Kotlin. I am currently working with an Android app from Punch Through:
(Blog: https://punchthrough.com/android-ble-guide/)
(GitHub: https://github.com/PunchThrough/ble-starter-android)
The app connects with a BLE peripheral and allows the user to enter text to send to the peripheral via UART.
I am struggling interpreting what the following code means / does:
with(hexField.text.toString()) {
if (isNotBlank() && isNotEmpty()) {
val bytes = hexToBytes()
ConnectionManager.writeCharacteristic(device, characteristic, bytes)
}
}
Where hexField.text.toString() is the text entered in the EditText field by the user,
and
where hexToBytes() is defined as:
private fun String.hexToBytes() =
this.chunked(2).map { it.toUpperCase(Locale.US).toInt(16).toByte() }.toByteArray()
I have tried this a few times, always entering “111” and have am using Timber() to output the result of bytes. This result varies every time, for example:
[B#2acf801
[B#476814a
[B#e9a70e5
[B#10172a0
So, I assume that only the first three characters are relevant, and somehow there is no end of line / string information.
So perhaps I am only interested in: [B#.......
B# = 0x 5B 42 40
Hex: 5B4240
Dec: 5980736
Bin: 10110110100001001000000
So then I try (and fail) to interpret / breakdown what this code might be doing.
The first thing I struggle with is understanding the order of operation.
Here's my guess....
Given EditText entry, in this case I entered "111"
First:
this.chunked(2)
would produce something like:
"11 and "01"
Second, for each of the two items ("11 and "01"):
it.toUpperCase(Locale.US).toInt(16).toByte()
would produce byte values:
17 and 1
Third:
.map .toByteArray()
Would produce something like:
[1,7,1]
or
[0x01, 0x07, 0x1]
or
[0x0x31, 0x37, 0x31]
So, as you can see, I am getting lost in this!
Can anyone help me deconstruct this code?
Thanks in advance
Garrett
I have tried this a few times, always entering “111” and have am using Timber() to output the result of bytes. This result varies every time
The output when you try to print a ByteArray (or any array on the JVM) doesn't show the contents of the array, but its type and address in memory. This is why you don't get the same result every time.
In order to print an array's contents, use theArray.contentToString() (instead of plain interpolation or .toString()).
Regarding the interpretation of the code, you almost got it right, but there are a few mistakes here and there.
this.chunked(2) on the string "111" would return a list of 2 strings: ["11", "1"] - there is no padding here, just the plain strings with max size of 2.
Then, map takes each of those elements individually and applies the transformation it.toUpperCase(Locale.US).toInt(16).toByte(). This one makes the string uppercase (doesn't change anything for the 1s), and then converts the string into an integer by interpreting it in base 16, and then truncates this integer to a single byte. This part you got right, it transforms "11" into 17 and "1" into 1, but the map {...} operation transforms the list ["11", "1"] into [17, 1], it doesn't take the digits of 17 individually.
Now toByteArray() just converts the List ([17, 1]) into a byte array of the same values, so it's still [17, 1].

Query using LIKE isn't working using GreenDAO

I have a table which a column is a string with three characters, each character has a value 0 or 1. I'd like to select those rows according to the case.
I'd like to perform a query like that:
SELECT * FROM Item WHERE group_type LIKE ?
? can be 100 or 101 or 011 or 111 or 001. A combination with 0 and 1 in three characters.
I'm trying to query using LIKE
WhereCondition where = null;
switch (condition) {
case case1:
where = ItemDao.Properties.GroupType.like("1%");
break;
case case2:
where = ItemDao.Properties.GroupType.like("%1%");
break;
case case3:
where = ItemDao.Properties.GroupType.like("%1");
break;
}
List<Item> items = itemDao.queryBuilder().where(where).list();
case1 is returning everything that starts with 1 as expected.
case3 is returning everything that ends with 1 as expected.
case2 is returning everything! It doesn't metter the value in the beggining, middle or end. It's returning everything.
case1 and case3 are working fine. However, case2 isn't working. Is there any problem with that?
No. "%1%" is supposed to return everything where "1" occurs. It can be "100", "010" or "101", but not "000".
From the sqlite like clause reference page:
The percent sign represents zero, one, or multiple numbers or characters. The underscore represents a single number or character. These symbols can be used in combinations.
By saying %1% you are searching for elements that have at least one number 1, regardless where it may be. This is mostly because % meaning zero, one or multiple occurrences. This is further explained in that link by the following example:
WHERE SALARY LIKE '%200%'
Finds any values that have 200 in any position
So we can see that indeed you are getting the expected behavior.

Dynamic Variable Names for Android App

I have an activity with 4 TextView elements with ids of Mon1, Mon2, Mon3, Mon4.
Is it possible to create a loop in the MainActivity.java code where I can perform, for example, a setText action on each of the 4 ids without having to list them out one-by-one.
ie. Mon*X*.setText=""; (where X is a value from 1 to 4).
I guess to take this one step further, if the ids were actually Mon1, Mon2, Mon3, Mon4, Tue1, Tue2, Tue3, Tue4, Wed1 .........Sun1, Sun2,Sun3, Sun4. Could a loop be created to not only change the number 1..4 but also use an array for the Mon, Tue, Wed etc.
The end result being some sort of loop that can do setText on ALL the ids that I need rather than 28 individual setText commands.
You could do something like:
TextView Mon1; //and do whatever with it
TextView Mon2; //And so on
TextView[] tv = {Mon1, Mon2, Mon3, /*etc*/}
int i = 0;
void doSomething(){while(i<=/*number of TextViews*/){tv[i].setText("BLAH");i++;}}
I hope this helped :D
Is it possible to create a loop in the MainActivity.java code where I
can perform, for example, a setText action on each of the 4 ids
without having to list them out one-by-one.
Yup. Use an array.
To take it another step further, use another array. It's what they're made for.
(By array, I mean an ArrayList, HashMap, dictionary, array, or any other data structure like that).

Is there an easier way to compare a large list of items?

I have an extremely long list of items (over 200) and a database that displays the list. I have an on click event that will compare that if the first item is an "apple" then when you click it, facts come up about an "apple". The problem is that this list isn't a SET list, meaning the the word "apple" could be in the 1st spot or it could be in the 18th spot.
I started doing an if statement that compares like this:
case 0:
if (text.equals("apple")) {
[show facts about apple]
} else if (text.equals("orange")) {
[show facts about orange]
//this would continue on to compare the ENTIRE LIST (about 500 lines per case)
break;
The problem is that i got an error that states:
The code of method onListItemClick(ListView, View, int, long) is exceeding the 65535 bytes limit
There must be an easier way to do this, right?
You can put the facts in a database and use the items to index the table. Then, your if will be evaluated by the database. It will look like select fact from facts where item='apple'. Might that help? It would also easily be possible to add, remove or alter information. Also, the look-up (the if-evaluation) is very fast with the aid of database indexes.
First of all, to just solve your "method too long" problem, there are several ways.
#1 move all your description into strings.xml.
if (text.equals("apple")) {
result = getResources().getString(R.string.apple_description);
}
#2 move your if-else into a separated method.
case 0:
mydescription = getDescription(text); // getDescription() is the big if-else you have
BUT..... it is still very bad to code in such a way.
Please consider following:
#1 Create a HashMap for name and description.
Apple - Description For Apple
Orange - Description For Orange
#2 In your list adapter, set a tag as indicator.
view.setTag("apple");
#3 In your onListItemClick, read this tag and get description.
String text = view.getTag();
String description = myhashmap.get(text).toString();
// If your hashmap is mapping name and string resource id then:
String description = getResources().getString(Integer.parseInt(myhashmap.get(text)));

how to perform a condition the basis of item selection on two spinners?

I have two spinners in my app. I want that if i select option "first" from spinner 1 and option "second" from spinner 2, then the action gets performed. But it show "NUMBERFORMATEXCEPTION".
Here's the code
if (((spinner.getItemAtPosition(pos).toString()=="first" &&
(s2.getItemAtPosition(id).toString()=="second"))))
{
tv.setText(String.valueOf(gmtomilli(x)));
}
This code has the error, if i omit this code, then the app works fine,without action
Do String comparison using equals.
spinner.getItemAtPosition(pos).toString()=="first"
instead use:
spinner.getItemAtPosition(pos).toString().equals("first")
Similarly for:
s2.getItemAtPosition(id).toString()=="second"
instead use:
s2.getItemAtPosition(id).toString().equals("second")
Read this for more information.
== compares references,not the values. In your case, you want to check for the value equality, not the reference equality.
EDIT:
Since you have mentioned that your code is generating NumberFormatException, I probably believe that either pos or id are of String type generating the NumberFormatException.
EDIT 2:
As per the your comment:
float x=Float.parseFloat(String.valueOf(et.getText()));
Your getText() is returning a String that can't be actually parsed into a float. Try checking if the content is actually a float in String format.
Besides, use String.trim() before parsing to ensure your String doesn't contain any leading or trailing whitespaces that's generating the NumberFormatException.

Categories

Resources