Android BLE特性getValue在API级别33中被弃用,我可以通过什么正确的方式获取该值?

7ivaypg9  于 2023-05-05  发布在  Android
关注(0)|答案(2)|浏览(465)

Android BLE特性getValue在API级别33中被弃用,并且在developer.androidBluetoothGattCharacteristic中表示我们可以使用BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)代替
但正如我用代码检查的那样,developer.android也提到它返回一个布尔值,而不是byteArray BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)
什么是正确的方法可以得到这个值?

bq3bfh9z

bq3bfh9z1#

API〈= 32时:

每个BluetoothGattCharacteristic对象都包含一个value字段,该字段由应用程序(写入时)和蓝牙堆栈(阅读/接收通知时)更改。
要写入特征值,首先设置value字段(通过使用setValue setter方法),然后通过调用writeCharacteristic执行实际写入。
要读取特征值,请调用readCharacteristic(这会触发对远程设备的读取请求),并在响应到达时调用的onCharacteristicRead回调中,通过获取value字段(通过调用getValue getter方法)来检索值。
当使用onCharacteristicChanged接收到通知或指示时,以与读取回调相同的方式检索值。
请注意,getValue只是返回存储在BluetoothGattCharacteristic对象的本地value字段中的任何当前值。它不会触发对远程设备的新读取请求。通常,getValue不应该被调用,除非在onCharacteristicChangedonCharacteristicRead回调中立即调用。

API〉= 33时:

新的API不使用任何value字段。相反,该值作为参数传递。
要写入特征值,只需调用writeCharacteristic并将值作为参数传递。
要读取特征值,首先调用readCharacteristic。当响应从远程设备到达时,onCharacteristicRead回调将以刚刚读取的值作为参数进行调用。
当使用onCharacteristicChanged接收到通知或指示时,该值将作为参数传递给该方法。

新旧设备兼容应用

请注意,为新API编译的代码在旧设备上运行时将无法正常工作。您会注意到,根本不会调用新的回调重载。你基本上有两个选择:
1.坚持使用旧的API,忽略新的API。只要这个旧的API没有被完全删除,代码就会像以前一样工作,即使在新的设备上也是如此。
1.实现两个API,* 不 * 调用super.onCharacteristicChanged(...)等。对于旧设备,将(仅)调用旧API方法,对于新设备,将(仅)调用新API方法。我建议你有身体onCharacteristicChanged(gatt, characteristic, characteristic.getValue());等。在旧的回调API方法中,手动将数据传递给新的回调,并将所有逻辑放在新的回调API方法中。

为什么更新此API?

请考虑您具有允许通知和写入的特性的情况。如果Android应用在通知到达的确切时间写入特征,则会存在关于特征对象的value字段的竞争条件,这意味着您可能会写入刚刚通知的值,或者被通知您即将写入的值。新的API通过直接将值作为参数传递来解决这个问题。

ws51t4hk

ws51t4hk2#

仅调用BluetoothGatt.readCharacteristic()是不够的,您还必须在管理BLE事务的任何地方实现BluetoothGattCallback接口,以便从远程BLE设备获取值。
假设您在名为MyBluetoothManager的类中管理事务。
BluetoothGatt.readCharacteristic()函数不会立即返回值,而是启动蓝牙读取事务,远程设备将在稍后进行异步响应。它的工作原理类似于互联网连接,您向服务器发出请求以获取一些数据,然后服务器稍后异步响应,最后您在其响应回调中处理数据。
调用readCharacteristic方法时返回的值是一个指示读取操作是否成功启动的值。

编辑新增了onCharacteristicRead两种方法,支持API 33以下和API 33+。

下面是MyBluetoothManager最小代码示例:

class MyBluetoothManager implements BluetoothGattCallback {
    
    public interface ReadListener {
        void onValueObtained(BluetoothGattCharacteristic characteristic, byte[] value);
    }
    
    private ReadListener readListener;
    
    // Instantiate the following vars in the relevant callbacks
    private BluetoothGatt connectedPeripheral;
    private BluetoothGattCharacteristic interestedCharacteristic;
    ...
    
    // A wrapper function for #BluetoothGatt.readCharacteristic. It also
    // a ReadListener type parameter in order to notify the caller asynchronously.
    public boolean readCharacteristic(BluetoothGattCharacteristic characteristic,
                                      ReadListener readListener)
    {
        if(connectedPeripheral == null || characteristic == null) return;
        this.readListener = readListener; // register the listener from activity
        return connectedPeripheral.readCharacteristic(characteristic);
    }
    
    
    public BluetoothGattCharacteristic getInterestedCharacteristic() {
        return interestedCharacteristic;
    }
    ...
    
    // Other callbacks goes here...
    /*
     * This callback method is added in API 33
     */
    @Override
    public void onCharacteristicRead (BluetoothGatt gatt, 
                                      BluetoothGattCharacteristic characteristic, 
                                      byte[] value, 
                                      int status)
    {
        // According to the new API you can only get the value in this callback.
        // You can copy and deliver value to another parts of application,
        // or handle it instantly here.
        
        if(readListener != null) // Notify the activity for the new obtained value
            readListener.onValueObtained(characteristic, value);
    }
    
    /* The older callback method that is deprecated in API 33 */
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, 
                                        BluetoothGattCharacteristic characteristic) {
        if (android.os.Build.VERSION.SDK_INT < 33) {
            if(readListener != null) {
                readListener.onValueObtained(characteristic, characteristic.getValue());
            }
        }
    }
    
    // Other callbacks goes here...
    ...
}

下面是一个从Activity调用MyBluetoothManager.readCharacteristic方法的示例:

class BLEControlActivity extends AppCompatActivity {
    
    private MyBluetoothManager mBluetoohManager;
    ...
    
    private Button readButton;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mBluetoohManager = // instantiate depending on your implementation
        ...
        readButton = findViewById(R.id.buttonRead);
        readButton.setOnClickListener((v) -> {
            if(mBluetoohManager.isConnected()) {
                mBluetoohManager.readCharacteristic(
                    mBluetoohManager.getInterestedCharacteristic(),
                                                    (characteristic, value) -> {
                                                        // Handle the reead value
                                                    }
                )
            }
        });
    }
}

相关问题