BLE 广告在 Android 中发生变化

BLE Advertisements changing in Android

我对 android 和 BLE 还很陌生。目前,我正在尝试通告一个数据包,该数据包会通过 BLE 在 android 中定期更改。我使用了 https://source.android.com/devices/bluetooth/ble_advertising.

中可用的以下代码
BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
        AdvertisingSetParameters parameters = (new AdvertisingSetParameters.Builder())
                .setLegacyMode(true) // True by default, but set here as a reminder.
                .setConnectable(false)
                .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
                .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_HIGH)
                .build();
        AdvertiseData data = (new AdvertiseData.Builder()).setIncludeDeviceName(true).build();

        final AdvertisingSet[] currentAdvertisingSet = new AdvertisingSet[1];
        //final AdvertisingSet[] currentAdvertisingSet = {null};
        AdvertisingSetCallback callback = new AdvertisingSetCallback() {
            @Override
            public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
                Log.i(LOG_TAG, "onAdvertisingSetStarted(): txPower:" + txPower + " , status: "
                        + status);
                currentAdvertisingSet[0] = advertisingSet;
            }

            @Override
            public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
                Log.i(LOG_TAG, "onAdvertisingDataSet() :status:" + status);
            }

            @Override
            public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
                Log.i(LOG_TAG, "onScanResponseDataSet(): status:" + status);
            }

            @Override
            public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
                Log.i(LOG_TAG, "onAdvertisingSetStopped():");
            }
        };

        //start advertising
        advertiser.startAdvertisingSet(parameters, data, null, null, null, callback);

        //change the advertising packet
        currentAdvertisingSet[0].setAdvertisingData(new AdvertiseData.Builder().setIncludeDeviceName(true).setIncludeTxPowerLevel(true).build());

但是当我尝试将新的广告数据分配为最后一行时,我得到了

Attempt to invoke virtual method 'void android.bluetooth.le.AdvertisingSet.setAdvertisingData(android.bluetooth.le.AdvertiseData)' on a null object reference

错误和应用关闭,setLegacyMode true 和 false。 但是我已经在 public void onAdvertisingSetStarted 函数中分配了 advertisingSet 。 我需要在这里做什么?

显示的代码导致 NullPointerException 的原因是因为它试图在您为该数组元素赋值之前访问 currentAdvertisingSet[0]

当代码用 final AdvertisingSet[] currentAdvertisingSet = new AdvertisingSet[1]; 初始化它时,数组的内容会被初始化,每个元素都设置为 null。在 AdvertisingSetCallback 执行之前,代码不会将 currentAdvertisingSet[0] 初始化为非空值。这是异步的,并且会在 调用 advertiser.startAdvertisingSet(...).

之后的某个时间发生

问题是当下一行 currentAdvertisingSet[0].setAdvertisingData(...) 几微秒后执行时,这个回调还没有发生。当它执行时,currentAdvertisingSet[0] 元素还没有被初始化——它仍然是空的。这就是代码崩溃的原因。

要解决此问题,您必须等待 currentAdvertisingSet[0] 初始化完成后再使用。您当然可以添加 if (currentAdvertisingSet[0] != null) 之类的检查来防止崩溃,但在显示的代码中,这永远不会成立,因此代码永远不会执行。

最终,您将需要移动更改广告集的代码,以便它在以后执行。您可以将这段代码放在回调中,但这对您的用例来说可能没有意义——开始广告然后立即将其更改为其他内容可能没有意义。