Search code examples
rx-java2reactivexrxandroidble

In RxAndroidBle, How do return ObservableSource<out TypeVariable<R>!>! from Observable.combineLatest() instead of Unit?


I am trying to get all characteristics from the Device Information service on a specific device. I can pick any single device and get the characteristic from it using:

                    deviceConnection =
                        device.establishConnection(true)
                            .flatMapSingle { rxBleConnection ->
                                rxBleConnection
                                    .readCharacteristic(java.util.UUID.fromString(c.uuid))
                            }
                            .subscribe(
                                { onConnectionSuccess(it, v) },
                                { onConnectionFailure(it, v) })

The issue is when I attempt to read multiple characteristics at once. I have tried to use the example documentation from Polidea's blog detailing multiple reads, multiple questions on SO, and documentation for RxJava observables and I cannot figure out what I'm doing wrong.

The error I am getting from AndroidStudio is:

Type mismatch.
    Required: ObservableSource<out TypeVariable<R>!>!
    Found:    Unit

As far as I can tell I'm doing this the same way all of these other examples are. The code I am attempting to read multiple characteristics is below:

device = BleApplication.getRxBleClient(this)
            .getBleDevice(macAddress)

        deviceConnection =
            device.establishConnection(false)
                .flatMap { rxBleConnection ->
                    Observable.combineLatest(
                        rxBleConnection
                            .readCharacteristic(jUuid(ManufacturerNameString.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(ModelNumberString.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(SerialNumberString.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(HardwareRevisionString.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(FirmwareRevisionString.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(SoftwareRevisionString.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(SystemID.toString())),
                        rxBleConnection
                            .readCharacteristic(jUuid(PnPID.toString())),
                        ::BoseDevice
                    )
                }
                .take(1)
                .subscribe({}, {}) //onConnectionSuccess(it) }, { onConnectionFailure(it) })

The class I've trying to feed the observables into:

internal class BoseDevice(
    val manufacturer: ByteArray,
    val modelNumber: ByteArray,
    val serialNumber: ByteArray,
    val hardwareRevision: ByteArray,
    val firmwareRevision: ByteArray,
    val softwareRevision: ByteArray,
    val systemID: ByteArray,
    val pnpID: ByteArray
)

These are the my dependencies declared in my gradle file:

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation "com.polidea.rxandroidble2:rxandroidble:1.11.1"
    implementation 'com.google.android.material:material:1.1.0'
    implementation "io.reactivex.rxjava2:rxjava:2.2.19"
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'

Solution

  • These type problems are notoriously hard to debug with Kotlin (at least now with 1.3.70). You have two mistakes that prevent you from having working code:
    First — you try to .combineLatest() objects of type Single, not Observable. So you should use either .flatMapSingle() combined with Single.zip() or change each read to an Observable like this rxBleConnection.readCharacteristic().toObservable().
    Second — you try to use constructor as a Function8 object which apparently cannot be used this way. You have to create this function by hand

    device.establishConnection(false)
        .flatMapSingle { rxBleConnection ->
            Single.zip(
                rxBleConnection
                    .readCharacteristic(jUuid(ManufacturerNameString.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(ModelNumberString.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(SerialNumberString.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(HardwareRevisionString.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(FirmwareRevisionString.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(SoftwareRevisionString.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(SystemID.toString())),
                rxBleConnection
                    .readCharacteristic(jUuid(PnPID.toString())),
                Function8 { a, b, c, d, e, f, g, h -> BoseDevice(a, b, c, d, e, f, g, h)}
            )
        }
        .take(1)
        .subscribe({}, {})
    

    or

    device.establishConnection(false)
        .flatMap { rxBleConnection ->
            Observable.combineLatest(
                rxBleConnection
                    .readCharacteristic(jUuid(ManufacturerNameString.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(ModelNumberString.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(SerialNumberString.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(HardwareRevisionString.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(FirmwareRevisionString.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(SoftwareRevisionString.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(SystemID.toString())).toObservable(),
                rxBleConnection
                    .readCharacteristic(jUuid(PnPID.toString())).toObservable(),
                Function8 { a, b, c, d, e, f, g, h -> BoseDevice(a, b, c, d, e, f, g, h)}
            )
        }
        .take(1)
        .subscribe({}, {})