Android BluetoothGatt - 状态 133 - 注册回调函数

45
首先,我阅读了已解决:GATT回调无法注册并按照该帖子中建议的步骤尝试解决此问题,但未能成功。那里推荐的修复方法是直接或通过处理程序从主线程进行所有BLE调用。
我正在开发一款BLE应用程序,想要运行一个服务(每隔10秒从活动中调用一次)来执行以下任务:
1)Gets list of our products available to connect to (done, works)

2)For each available device:

          2a)connect to device
          2b)discover services
          2c)read 5 characteristics in this fashion:
             2c1)read characteristic
             2c2)onCharacteristicRead parse data
             2c3)when finished with data read next characteristic
             2c4)repeat until all are read (this is done using a state var and switch statement)
         2d)disconnect from device
         2e)connect to next device
         2f)repeat until all devices are read from
         2g)stopSelf()

所以问题是...一切都很好,但只有在短时间内。我可以执行整个服务启动{mainActivity中的startService(...);}到完成{服务中的stopSelf();}6次。

第7次我会得到BluetoothGatt注册回调失败的错误。我不确定为什么前6次成功运行,而第7次失败。

请记住,我正在从主线程进行所有BLE调用,并且在日志记录器中已从多个位置确认。

这是我的代码概述:

SERVICE.JAVA

private Handler handler = new Handler();
private BluetoothGatt cGatt = null;
private int unitIndex = 0; // keep track of currently connected unit
private int state = 0; //used to keep track of which characteristic to read next

public int onStartCommand(Intent intent, int flags, int startId) 
{
    Log.i(TAG, "Service Started...");
    //get ArrayList of units

    if(units.size > 0)
        handler.post(connectNextRunnable); //calls connectNextDevice()
    else
        stopSelf();   
}

private Runnable discoverServices = new Runnable()
{
    public void run()
    {
        cGatt.discoverServices();
    }
}

private Runnable readNextValue = new Runnable()
{
    public void run()
    {
        BluetoothGattCharacteristic c = null;
        switch(state)
        {
            //set c to appropriate characteristic
        default: // all characteristics read
            unitIndex++;
            handler.post(connectNextRunnable)
            return
        }

        cGatt.readCharacteristic(c);
    }
}

private void connectNextDevice()
{
    if(unitIndex == 0)
        store System.nanoTime in variable

    if(unitIndex >= units.size) //finished will all units
        stopSelf();

    if(unitIndex < units.size)
        cGatt.disconnect //if null
        cGatt.connectGatt(this, false, gattCallback)
}

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() 
{
    public void onConnectionStateChange() 
    {
        handler.post(discoverServices);
    }

    public void onServicesDeiscovered() 
    {
        handler.post(readNextValue);
    }

    public void onCharacteristicRead() 
    {
        ParseData();
    }

    private void ParseData()
    {
        //do stuff with data
        handler.post(readNextValue);
    }
}

如我所说,所有BLE的操作都是通过一个处理程序从主线程调用的。服务成功地运行了6次,但第7次我遇到了“无法注册回调”的错误。

如果您认为相关,我可以提供更多的logcat信息。在原始帖子中,我没有提供它,因为我正在输出大量信息以验证数据接收等内容。

以下信息是我的服务从开始到结束的第7次运行的logcat信息。

08-15 12:00:10.746: I/PMIQ BTS(32027): Service Started...
08-15 12:00:10.746: I/PMIQ BTS(32027): Units: 1
08-15 12:00:10.746: D/AbsListView(32027): unregisterIRListener() is called 
08-15 12:00:10.766: I/PMIQ BTS(32027): Connecting to next device...
08-15 12:00:10.766: I/PMIQ BTS(32027): Unit index = 0
08-15 12:00:10.766: I/PMIQ BTS(32027): Connecting to pmIQ-IQ130_D93A
08-15 12:00:10.766: I/System.out(32027): main
08-15 12:00:10.766: D/BluetoothGatt(32027): connect() - device: 00:1E:C0:19:D9:3A, auto: false
08-15 12:00:10.766: D/BluetoothGatt(32027): registerApp()
08-15 12:00:10.766: D/BluetoothGatt(32027): registerApp() - UUID=e9d10870-4b09-451c-a9fa-c6b5f3594a77
08-15 12:00:10.766: I/BluetoothGatt(32027): Client registered, waiting for callback
08-15 12:00:10.766: D/BluetoothGatt(32027): onClientRegistered() - status=133 clientIf=0
08-15 12:00:10.766: I/PMIQ BTS(32027): CONECTION STATE CHANGED...Binder_2
**08-15 12:00:10.766: E/BluetoothGatt(32027): Failed to register callback**
08-15 12:00:10.766: I/PMIQ BTS(32027): Could not connect to null ... 257
08-15 12:00:10.766: I/PMIQ BTS(32027): Connecting to next device...
08-15 12:00:10.766: I/PMIQ BTS(32027): Unit index = 1
08-15 12:00:10.766: I/PMIQ BTS(32027): ******************************
08-15 12:00:10.766: I/PMIQ BTS(32027): Start Time: 4360642409647
08-15 12:00:10.766: I/PMIQ BTS(32027): End Time: 4360648970925
08-15 12:00:10.766: I/PMIQ BTS(32027): Difference: 6561278
08-15 12:00:10.766: I/PMIQ BTS(32027): Time to complete: 6
08-15 12:00:10.766: I/PMIQ BTS(32027): ******************************
08-15 12:00:10.876: I/PMIQ BTS(32027): ...Service Destroyed

如果你看到了这里,谢谢!我找不到关于status=133的任何信息?!它只会在回调失败时出现。其他情况下都是status=0。

08-15 12:00:10.766: D/BluetoothGatt(32027): onClientRegistered() - status=133 clientIf=0

如果有人能回答这个问题,那将对我非常有帮助。或者如果有人能告诉我为什么它只运行了6次。任何洞见或直觉都可能有所帮助!

谢谢大家!


这里可能有一个答案:https://code.google.com/p/android/issues/detail?id=68538。然而,我要等到周一才能测试,因为似乎我没有正确地从设备上断开连接。 - Chris K
它对我没有用,即使在 Android 中调用 close 后仍然出现错误 133。 - prasanthMurugan
6个回答

65

好的,我已经找到了解决方法。问题主要是因为我在阅读BluetoothGatt文档时疏忽了。我调用了.disconnect(),但没有调用.close()。由于Galaxy s4一次只能处理6个连接,我的服务只运行了6次。在我的代码中添加.close()允许正确关闭连接并释放被使用的连接。

这个问题促使我更加仔细地阅读文档!

因此,请记得在您的BluetoothGatt对象上使用.close(),如果您需要连接到同一设备(们)!


16
133代表GATT_ERROR(来源:https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-4.4.4_r2.0.1/stack/include/gatt_api.h) - PaulT
2
是的,你说得对。但这也没有帮助,一段时间后会出现Gatt_Error(错误代码:133)。有什么建议吗? - CoDe
4
答案是正确的,但它并不能解决所有可能的错误情况......至少对我使用过的心爱的133来说是这样。 - andrea.rinaldi
3
对于错误代码为133,唯一能做的就是多次重试。这是已知的唯一解决方案。 - IgorGanapolsky
1
@ck1221,有关S4仅处理6个设备的文档在哪里?应该是7个,对吧? - Bryan Bryce
显示剩余6条评论

31
在经过数月的研究和苦思冥想之后,我找到了一个解决方案,这通常不被讨论。
您正常的连接请求看起来像这样:
cGatt.connectGatt(this, false, gattCallback);

connectGatt命令还有另一种版本,带有第四个参数。此参数指定您要连接的蓝牙设备类型。我添加了“2”以指定我是通过Bluetooth LE连接的(称为“transport”,如果我的解释不正确,请原谅,但这解决了我的所有问题)。

尝试一下:

cGatt.connectGatt(this, false, gattCallback, 2);

然后,砰的一声,现在我的#133噩梦结束了(我祈祷)!


11
注意,使用transport参数的connectGatt方法需要API 23及以上版本。您可以使用常量BluetoothDevice.TRANSPORT_LE来代替硬编码值2。 - Bubu
1
我不知道为什么在使用这行代码两年没有问题后,现在在2022年需要添加它。我猜可能是我的硬件的操作系统更新改变了BLE的某些内容,以至于现在连接到我的硬件需要这个代码,但我真的很想知道为什么。 - Nonlin

16

安卓操作系统 < 6.0:

mBluetoothDevice.connectGatt(context, false, callback);

安卓操作系统版本 >= 6.0:

mBluetoothDevice.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE);

最终,需要硬件设备来彻底解决这个问题。


感谢您提供这么有价值的答案。 它对我有用。 但是如果您能提供更多关于这个逻辑的文档,那将非常有帮助。 - vinay shetty
我不知道为什么在使用这行代码两年没有问题后,现在在2022年需要添加它。我猜可能是我的硬件的操作系统更新改变了BLE的某些内容,以至于现在连接到我的硬件需要这个代码,但我真的很想知道为什么。 - Nonlin

2
  • 在一些设备上,可以通过以下方式解决: mBluetoothDevice.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE);

  • 在三星S7、A8等某些设备上,问题出现在ScanSettings.Builder().setReportDelay(400) // 或 500ms。这个值不应该为0或更高,如1000ms。 ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) .setReportDelay(400) .build();

"最初的回答"

1
尝试使用下一个解决方法:
private static boolean gatt_status_133 = false;

final Handler handler = new Handler();

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

    if (newState == BluetoothProfile.STATE_CONNECTED) {
        mConnectionState = STATE_CONNECTED;
        Log.i(TAG, "Connected to GATT server.");
        // Attempts to discover services after successful connection.
        Log.i(TAG, "Attempting to start service discovery:" +
                mBluetoothGatt.discoverServices());

    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
        if(status == 133)
        {
            gatt_status_133=true;
        }
        else{
            mConnectionState = STATE_DISCONNECTED;
            Log.i(TAG, "Disconnected from GATT server."); 
        }
    }
}


@RequiresApi(api = Build.VERSION_CODES.M)
public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
            && mBluetoothGatt != null) {
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
        if (mBluetoothGatt.connect()) {
            mConnectionState = STATE_CONNECTING;
            return true;
        } else {
            return false;
        }
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    if (device == null) {
        Log.w(TAG, "Device not found.  Unable to connect.");
        return false;
    }

    mBluetoothGatt= device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress = address;
    mConnectionState = STATE_CONNECTING;

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if(gatt_status_133)
            {
                Log.d(TAG, "Catch issue");
                connect(address);
                gatt_status_133=false;
            }
        }
    }, 4000);

    return true;
}

1

不知何故,BluetoothLeScanner.startScan() 有所帮助

private final Handler mMainHandler = new Handler(Looper.getMainLooper());
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    if (newState == BluetoothProfile.STATE_CONNECTED) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothAdapter.isEnabled() && mBleScanner != null) {
            mBleScanner.stopScan(mLeScanCallback);
        }
    } else if (status == 133 && newState == BluetoothProfile.STATE_DISCONNECTED) {
        if (D) Log.e(TAG, "connectGatt status == 133");
        mMainHandler.post(mDisconnectRunnable);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothAdapter.isEnabled()) {
            mBleScanner = mBluetoothAdapter.getBluetoothLeScanner();
            mBleScanner.startScan(null, new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(),
                    mLeScanCallback);
        }
        mMainHandler.postDelayed(mConnectRunnable, 10000);
    }
}

private ScanCallback mLeScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        if (result.getDevice().getAddress().equals(mBluetoothDeviceAddress)) {
            mMainHandler.post(mConnectRunnable);
            if (mBleScanner != null) {
                mBleScanner.stopScan(mLeScanCallback);
                mBleScanner = null;
            }
        }
    }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接