question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Android - observer.collect throws NoSuchElementException

See original GitHub issue

I’m trying to read some data of a UART Service that provides a “write without response” and a “notify” characteristic. I can write to it fine using cable but Kable but get the following error when using observer.collect { ... } to subscribe to notifications.

java.util.NoSuchElementException: Collection contains no element matching the predicate.

The characteristic works fine to read using other apps and sends out data about once a second. As probably will be apparent from my sample code below I’m fairly new to Kotlin but as far as I understand after reading up and digging through the source code I can’t see why this error is produced.

I looked at issue 38 but since I go through the steps to get the characteristic I get this error even if it is discovered. Or did i misunderstand the cause of that issue?

The characteristic and observer objects looks fine to me, what I can notice is that the

Sample code

bluetoothScope.launch {
            val peripheral: Peripheral? = getPeripheral() // Get Peripheral using Scanner()
            if (peripheral != null) {
                peripheral.connect()
                val characteristic = peripheral.services
                        ?.first { service -> service.serviceUuid == UUID.fromString(UART_SERVICE)}
                        ?.characteristics?.first { characteristic ->
                            characteristic.characteristicUuid == UUID.fromString(RX_CHARACTERISTIC_UUID)
                        }
                if (characteristic != null ) {
                    val observer = peripheral.observe(characteristic)
                                try {
                                    observer.collect { data ->
                                        Log.d(TAG, data)
                                    }
                                } catch (e: NoSuchElementException) {
                                    Log.d(TAG, "Error: $e")
                                }
                }
                peripheral.state?.collect { state ->
                    when (state) {
                        State.Connected -> {
                            Log.d(TAG, "Connected")
                        }
                        else -> Log.d(TAG, "Not Connected")
                    }
                }
            }

        }
    }

Scan result

DiscoveredService(serviceUuid=6e400001-b5a3-f393-e0a9-e50e24dcca9e, 
characteristics=[
    DiscoveredCharacteristic(
        serviceUuid=6e400001-b5a3-f393-e0a9-e50e24dcca9e,
        characteristicUuid=6e400003-b5a3-f393-e0a9-e50e24dcca9e, 
        descriptors=[]), 
    DiscoveredCharacteristic(
        serviceUuid=6e400001-b5a3-f393-e0a9-e50e24dcca9e, 
        characteristicUuid=6e400002-b5a3-f393-e0a9-e50e24dcca9e, 
        descriptors=[])]
)]

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:15 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
twyattcommented, Dec 23, 2020

Your issue is actually closely related to #38, in that I believe you’re still being hit by the internal characteristic lookup failure within write or read, despite having retrieved the characteristic object from the discovered services.

Definitely a shortcoming in how the write and read functions retrieve the platform characteristic object: The services property converts the list of services to List<DiscoveredService>, whereas DiscoveredService only holds UUID details about the service (the reference to the actual platform service object is not held, to ensure that library consumers don’t hold on to/leak the platform’s service/characteristic objects).

Unfortunately this means that a lookup (in Peripheral’s internal service cache) is still performed even when manually finding the service/characteristic yourself (as you have done).

For Android, in the future, we may consider holding a weak reference in the services/characteristics provided by services property, making the lookup only necessary if the weak reference is lost.

In the mean time, I’ll be sure and get #38 closed out soon and push a SNAPSHOT or get another version published. It will at least give you a clearer picture of what is going wrong. Additionally, I’ll brainstorm other possible causes of the failure you’re seeing.

I haven’t investigated further but I assumed that the error was caused here in acquire() in Observers?

I suspect it is actually here (as described above):

https://github.com/JuulLabs/kable/blob/c750de57fa6b0ea3dbd148dee3807b95e4ec1719/core/src/jsMain/kotlin/Peripheral.kt#L207-L212

Please let me know if I can help you troubleshoot in anyway.

Thanks for the help and issue report. I’ll keep you posted.

1reaction
kostya29-strikersoftcommented, Dec 29, 2020

I have reproduced similar crash with SensorTag example when disconnect peripheral in during of connecting. You can reproduce this with my peripheral app attached here peripheral.apk.zip

java.util.NoSuchElementException: Collection contains no element matching the predicate. at com.juul.kable.PeripheralKt.bluetoothGattCharacteristicFrom(Peripheral.kt:269) at com.juul.kable.PeripheralKt.access$bluetoothGattCharacteristicFrom(Peripheral.kt:1) at com.juul.kable.AndroidPeripheral.startNotifications$core_debug(Peripheral.kt:193) at com.juul.kable.Observers$acquire$1.invokeSuspend(Observers.kt:45) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:342) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith$default(DispatchedContinuation.kt:263) at kotlinx.coroutines.internal.ScopeCoroutine.afterCompletion(Scopes.kt:27) at kotlinx.coroutines.JobSupport.continueCompleting(JobSupport.kt:933) at kotlinx.coroutines.JobSupport.access$continueCompleting(JobSupport.kt:28) at kotlinx.coroutines.JobSupport$ChildCompletion.invoke(JobSupport.kt:1152) at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1520) at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:323) at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:240) at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:903) at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:860) at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:825) at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:111) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:226) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7156) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Throw appropriate exception when performing I/O on ... - GitHub
Currently, when attempting to write/read a characteristic that was not discovered then it will throw a NoSuchElementException (as thrown by ...
Read more >
java.util.NoSuchElementException java code examples
Thrown when trying to retrieve an element past the end of an Enumeration or Iterator. Most used methods. <init>. Constructs a NoSuchElementException, saving...
Read more >
How to handle java.util.NoSuchElementException
java.util.nosuchelementexception is an unchecked exception. It does not need to be declared in a method's or a constructor's throws clause.
Read more >
Observable.empty() causes java.util.NoSuchElementException
data.isEmpty()) To my understanding this should just emit an empty list when mRetrofitObs throws an error, first will find this empty list and ......
Read more >
NoSuchElementException - Android Developers
Constructs a NoSuchElementException with null as its error message string. ... Called by the garbage collector on an object when garbage collection ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found