Home > Net >  Kotlin chunked and map
Kotlin chunked and map

Time:04-28

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

CodePudding user response:

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].

  • Related