setupNotification返回“已连接错误”,而没有发送连接请求

问题描述 投票:0回答:1

我正在使用RxAndroidBLE API制作一个带有一些BLE交互的Android应用程序。我遵循了https://github.com/Polidea/RxAndroidBle的示例指南和样本

我建立了与指定设备的BLE连接,稍后连接时我读取和写入特性没有问题,但是当我尝试设置电池电量特性的通知时,我得到以下throwable错误消息:已经连接到具有MAC地址XX的设备:XX ...”

我真的不明白该上下文中的错误,因为我可以在没有问题的情况下读取和写入特性。

我想在为特定目的初始读取其值后设置此特性的通知。

这是一个重现我的问题的示例代码:

private lateinit var device: RxBleDevice
private var connectionObservable: Observable<RxBleConnection>? = null
private var rxBleConnection: RxBleConnection? = null

private val connectionDisposable = CompositeDisposable()
private val connectionStateDisposable = CompositeDisposable()
private var notifyValueChangeSubscription = CompositeDisposable()


var enableBatteryNotificationRunnable: Runnable = Runnable {
  enableBatteryNotification()
}
private var myHandler = Handler()
val DELAY_BEFORE_ENABLE_NOTIFICATION: Long = 100


private fun connect() {
  connectionObservable = device.establishConnection(false)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

  connectionObservable?.let {
    connectionDisposable.add(it.subscribe(
      { rxBleConnection ->
        this.rxBleConnection = rxBleConnection
      },
      { _ ->
        Log.e("connect", "connexion error")                       
      })
    )
  }

  val state = device.observeConnectionStateChanges().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
  connectionStateDisposable.add(
    state.subscribe(
      { connectionState ->
        Log.i("connect", "connexion state :$connectionState")
        if(connectionState == RxBleConnection.RxBleConnectionState.CONNECTED) {
            myHandler.postDelayed(enableBatteryNotificationRunnable, DELAY_BEFORE_ENABLE_NOTIFICATION);
        }
      }
    )
    { _ ->
      Log.e("connection listener", "connexion state error")
    }
  )
}

private fun enableBatteryNotification () {
  connectionObservable?.let {
    var observableToReturn =  it
      .flatMap { it.setupNotification(UUID_BATTERY_LEVEL) }
      .doOnNext {
        Log.i("NOTIFICATION", "doOnNext")
      }
      .flatMap { it }
      .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

    notifyValueChangeSubscription.add(observableToReturn.subscribe({ bytes ->
        var strBytes = String(bytes)
        Log.i("NOTIFICATION", "value change: $strBytes")
      }, 
      { throwable ->
        Log.e("NOTIFICATION", "Error in notification process: " + throwable.message)
      })
    )
  }
}

在此先感谢任何帮助:)

android kotlin bluetooth-lowenergy rxandroidble
1个回答
1
投票

setupNotification返回“已连接错误”,而没有发送连接请求

实际上发出了两个连接请求 - 因此出错。来自RxBleDevice.establishConnection() Javadoc:

     * Establishes connection with a given BLE device. {@link RxBleConnection} is a handle, used to process BLE operations with a connected
     * device.

在您的代码中有两个订阅establishConnection() Observable

private lateinit var device: RxBleDevice
private var connectionObservable: Observable<RxBleConnection>? = null
private var rxBleConnection: RxBleConnection? = null

private val connectionDisposable = CompositeDisposable()
private val connectionStateDisposable = CompositeDisposable()
private var notifyValueChangeSubscription = CompositeDisposable()


var enableBatteryNotificationRunnable: Runnable = Runnable {
  enableBatteryNotification()
}
private var myHandler = Handler()
val DELAY_BEFORE_ENABLE_NOTIFICATION: Long = 100


private fun connect() {
  connectionObservable = device.establishConnection(false)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

  connectionObservable?.let {
    connectionDisposable.add(it.subscribe( // << Here is the first subscription
      { rxBleConnection ->
        this.rxBleConnection = rxBleConnection
      },
      { _ ->
        Log.e("connect", "connexion error")                       
      })
    )
  }

  val state = device.observeConnectionStateChanges().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
  connectionStateDisposable.add(
    state.subscribe(
      { connectionState ->
        Log.i("connect", "connexion state :$connectionState")
        if(connectionState == RxBleConnection.RxBleConnectionState.CONNECTED) {
            myHandler.postDelayed(enableBatteryNotificationRunnable, DELAY_BEFORE_ENABLE_NOTIFICATION);
        }
      }
    )
    { _ ->
      Log.e("connection listener", "connexion state error")
    }
  )
}

private fun enableBatteryNotification () {
  connectionObservable?.let {
    var observableToReturn =  it
      .flatMap { it.setupNotification(UUID_BATTERY_LEVEL) }
      .doOnNext {
        Log.i("NOTIFICATION", "doOnNext")
      }
      .flatMap { it }
      .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

    notifyValueChangeSubscription.add(observableToReturn.subscribe({ bytes -> // << Here is the second subscription
        var strBytes = String(bytes)
        Log.i("NOTIFICATION", "value change: $strBytes")
      }, 
      { throwable ->
        Log.e("NOTIFICATION", "Error in notification process: " + throwable.message)
      })
    )
  }
}

这种情况是人们学习RxJava的常见混乱。有three paths来解决你的情况。从最少到最多的工作:

Share the establishConnection Observable

可以与RxBleConnection共享一个RxReplayingShare。改变这个:

  connectionObservable = device.establishConnection(false)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

对此:

  connectionObservable = device.establishConnection(false)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .compose(ReplayingShare.instance())

Use the rxBleConnection: RxBleConnection? property

代替:

  connectionObservable?.let {
    var observableToReturn =  it
      .flatMap { it.setupNotification(UUID_BATTERY_LEVEL) }
      .doOnNext {
        Log.i("NOTIFICATION", "doOnNext")
      }
      .flatMap { it }
      .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

    notifyValueChangeSubscription.add(observableToReturn.subscribe({ bytes -> // << Here is the second subscription
        var strBytes = String(bytes)
        Log.i("NOTIFICATION", "value change: $strBytes")
      }, 
      { throwable ->
        Log.e("NOTIFICATION", "Error in notification process: " + throwable.message)
      })
    )
  }

做了:

  rxBleConnection?.let {
    var observableToReturn = rxBleConnection.setupNotification(UUID_BATTERY_LEVEL)
      .doOnNext {
        Log.i("NOTIFICATION", "doOnNext")
      }
      .flatMap { it }
      .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

    notifyValueChangeSubscription.add(observableToReturn.subscribe({ bytes -> // << Here is the second subscription
        var strBytes = String(bytes)
        Log.i("NOTIFICATION", "value change: $strBytes")
      }, 
      { throwable ->
        Log.e("NOTIFICATION", "Error in notification process: " + throwable.message)
      })
    )
  }

这是不鼓励的,因为你可能最终得到一个不再有效的RxBleConnection,因为它可能在调用enableBatteryNotification()之前已断开连接

Change the flow of your code to use a single .subscribe()

这是根据您的确切用例量身定制的自定义解决方案。不幸的是,您添加的信息不足以创建插入代码替换,但它可能看起来像这样:

device.establishConnection(false)
    .flatMap { connection ->
        Observable.merge(
            connection.readCharacteristic(uuid0).map { ReadResult(uuid0, it) }.toObservable(),
            connection.setupNotification(uuid1).flatMap { it }.map { NotifyResult(uuid1, it) }.delaySubscription(100, TimeUnit.MILLISECONDS)
        )
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        { /* handle ReadResult/NotifyResult */ },
        { /* handle potential errors */ }
    )

哪里ReadResultNotifyResultdata class采取UUIDByteArray

© www.soinside.com 2019 - 2024. All rights reserved.