Reputation: 612
So, Im quite new in Android development and also with working on observables. So what I want to achieve is that on every scan tick of the bluetooth scanner, the scanResult
gets checked and if its not in the list, the observed list scanned
gets an update, which checks something if this is valid and makes something.
My Problem is that the observe function just runs through once and then never again
2021-03-05 22:18:54.522 32057-32057/? D/devices: Got something []
2021-03-05 22:18:54.522 32057-32057/? D/devices: Start scan
2021-03-05 22:18:55.209 32057-32057/? D/devices: Checking Had128_1_1 in scanned
2021-03-05 22:18:55.212 32057-32057/? D/devices: adding Had128_1_1 in scanned
As far as I understood it right how this should work, he should here _scanned.value?.add(scanResult.device)
update and the observer should recognize that or am I wrong?
Could id be a problem with the lifecycleOwner?
It comes from the MainActivity to the composable with val lifecycleOwner = LocalLifecycleOwner.current
And yes, the function gets called in my composable (as I said, if i press the button, I can see on "Got Something []" that it runs through the first time)
private val _scanned: MutableLiveData<MutableList<BluetoothDevice>> =
MutableLiveData(mutableListOf())
private val scanned: LiveData<MutableList<BluetoothDevice>> get() = _scanned
private val lockScanCallback: ScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult?) {
super.onScanResult(callbackType, result)
result?.let { scanResult ->
if (fakeWhitelist.contains(scanResult.device.name)) {
Log.d("devices", "Checking ${scanResult.device.name} in scanned")
val search =
_scanned.value?.find { device -> device.name == scanResult.device.name }
if (search == null) {
Log.d("devices", "adding ${scanResult.device.name} in scanned")
_scanned.value?.add(scanResult.device)
}
}
}
}
}
fun listenForDevices(viewLiveCycleOwner: LifecycleOwner) {
scanned.observe(viewLiveCycleOwner, Observer { deviceList ->
Log.d("devices", "Got something $deviceList")
locationList.value.forEach { locationScaffold ->
val boxNames = locationScaffold.parcelBox.map { it.boxName }
val device = deviceList.last()
Log.d("devices", "$boxNames")
if (!boxNames.contains(device.name)) {
Log.d("devices", "Getting location for ${device.name}")
getLocation(device.name)
}
}
})
startScan()
}
Upvotes: 0
Views: 445
Reputation: 5980
Your mistake here is that you are never changing the value of the LiveData
. The value of LiveData
can be retrieved using LiveData.getValue()
and can only be set using LiveData.setValue()
and if you have a look over your implementation, you don't use the set method anywhere.
It is quite a common misconception that changing the state of an object will do something to it's reference, or somehow notify a class holding a reference to it, but this is not the case. If you think about a simplified version of LiveData
you can break it down into having these core functions:
The only way for it to be able to notify the observers is to expose a method/function that not only sets the value, but also notifies all the observers of the change if necessary.
So in your implementation, you retrieved the current value and changed its state, but never actually set a new value to the LiveData
.
So instead of
liveData.value?.add(newItem)
We would need to do something like
val list = liveData.value
list?.add(newItem)
_mutableLiveData.value = list
Upvotes: 1