In my kotlin app I want to move all the bluetooth related functionality into it's own class. While it is clear to me how to move a method into a separate class, I do not clearly see how to move a method into a class that updates data in the background.
How do I trigger the main activity after the bluetooth class receives some data in the background (currently a coroutine running a read loop) Here is for example the function that reads incoming bluetooth data. It works fine but updates the UI directly:
private suspend fun readBT() {
val buffer = ByteArray(1024)
var receivedSoFar = ""
/* Keep listening to the InputStream until an exception occurs or cancel is set. */
while (state == "connected") {
try {
/* nrOfBytes will hold the number of bytes in the buffer */
val nrOfBytes = inStream?.read(buffer)
/* add buffer content to current line */
receivedSoFar += String(buffer, 0, nrOfBytes!!)
/* until (incl) newline character */
if (receivedSoFar.contains("\n")) {
withContext(Dispatchers.Main) { txt_state.text = (receivedSoFar.dropLast(1)) }
receivedSoFar = ""
}
} catch (e: Exception) {
if (state == "connected") {
withContext(Dispatchers.Main) { txt_state.text = "error while reading bt data from Wallie" }
state = "error_during_read"
}
}
}
}
Your MainActivity
and the new BluetoothClass
should communicate through a callback. The callback can be a parameter of BluetoothClass
' constructor:
class BluetoothClass(
private val updateText: (String) -> Unit,
...
)
and MainActivity
will pass in an implementation of that lambda when instantiating BluetoothClass
:
bluetoothClass = BluetoothClass(updateText = { text -> txt_state.text = text })
Lastly, BluetoothClass
should invoke the lambda whenever it needs to update the text:
if (receivedSoFar.contains("\n")) {
withContext(Dispatchers.Main) { updateText(receivedSoFar.dropLast(1)) }
receivedSoFar = ""
}