Android蓝牙错误133 [英] Android Bluetooth error 133

查看:577
本文介绍了Android蓝牙错误133的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试连接到Android上的蓝牙设备.我在onClientConnectionState处理程序中收到状态133.我并非总是会收到此错误-有时连接正常.我无法确定引发问题的原因.重新启动设备和我的repro应用后,我什至立即拥有了它.

I'm attempting to connect to a Bluetooth device on Android. I'm receiving status 133 in my onClientConnectionState handler. I don't always get this error - sometimes it connects fine. I've not been able to put a finger on what triggers the problem. I've even had it immediately after restarting the device and my repro app.

我知道一些问题以及针对此问题的建议解决方案,包括(摘自此处此处

I'm aware of several questions and suggested solutions to this problem, including (from here, here, and here):

  • 将UI线程用于所有BT API
  • 确保完成后关闭GATT

但是我正在做所有这些.而且,我的设备是Nexus 5(运行Lollipop),据某些人甚至不需要BT交互就可以进入UI线程.

But I am doing all that. What's more, my device is a Nexus 5 (running Lollipop) which according to some shouldn't even need the BT interactions to be on the UI thread.

我整理了最简单的复制程序.它在C#中,但Java等效应该很明显:

I have put together the simplest possible repro. It's in C# but the Java equivalent should be obvious:

[Activity(Label = "BluetoothGatt133ErrorRepro", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    protected override void OnCreate(Android.OS.Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.Main);
        var button = FindViewById<Button>(Resource.Id.button);
        button.Click += this.OnClick;
    }

    private async void OnClick(object sender, EventArgs e)
    {
        Action<string> log = message => Console.WriteLine($"***** #{Environment.CurrentManagedThreadId} {message}");

        log("Beginning");

        var bluetoothManager = (BluetoothManager)Application.Context.GetSystemService(Context.BluetoothService);
        var adapter = bluetoothManager.Adapter;
        var scanner = adapter.BluetoothLeScanner;
        var callback = new Callback();
        var filters = new List<ScanFilter>();
        var settings = new ScanSettings.Builder()
            .SetScanMode(global::Android.Bluetooth.LE.ScanMode.LowLatency)
            .Build();

        log("Starting scan");
        scanner.StartScan(filters, settings, callback);

        var result = await callback.Result;
        log($"Got device: {result.Device.Name}");

        var remoteDevice = adapter.GetRemoteDevice(result.Device.Address);
        var gattCallback = new GattCallback(log);

        log("Connecting GATT");

        var gatt = remoteDevice.ConnectGatt(Application.Context, true, gattCallback);
        gatt.Connect();

        await gattCallback.Result;

        log("Disconnecting GATT");

        gatt.Close();
        gatt.Dispose();
    }

    private sealed class Callback : ScanCallback
    {
        private readonly TaskCompletionSource<ScanResult> result;

        public Callback()
        {
            this.result = new TaskCompletionSource<ScanResult>();
        }

        public Task<ScanResult> Result => this.result.Task;

        public override void OnBatchScanResults(IList<ScanResult> results)
        {
            foreach (var result in results)
            {
                this.HandleResult(result);
            }
        }

        public override void OnScanResult(ScanCallbackType callbackType, ScanResult result)
        {
            this.HandleResult(result);
        }

        public override void OnScanFailed(ScanFailure errorCode)
        {
            this.result.TrySetException(new InvalidOperationException($"Failed with error code {errorCode}."));
        }

        private void HandleResult(ScanResult result)
        {
            if (result.Device.Name.Contains("elided"))
            {
                this.result.TrySetResult(result);
            }
        }
    }

    private sealed class GattCallback : BluetoothGattCallback
    {
        private readonly Action<string> log;
        private readonly TaskCompletionSource<bool> result;

        public GattCallback(Action<string> log)
        {
            this.log = log;
            this.result = new TaskCompletionSource<bool>();
        }

        public Task<bool> Result => this.result.Task;

        public override void OnConnectionStateChange(BluetoothGatt gatt, GattStatus status, ProfileState newState)
        {
            this.log($"Connection state changed to {newState} with status {status}.");

            this.result.TrySetResult(true);
        }
    }
}

这是运行此命令的输出(我也已留在Android的BluetoothGatt源的输出中):

And here's the output from running this (I've left in the output from Android's BluetoothGatt source too):

***** #1 Beginning
***** #1 Starting scan
07-01 11:53:21.458 D/BluetoothLeScanner(10377): onClientRegistered() - status=0 clientIf=5
***** #1 Got device: elided
***** #1 Connecting GATT
07-01 11:53:22.833 D/BluetoothGatt(10377): connect() - device: 00:00:DE:AD:BE:EF, auto: true
07-01 11:53:22.833 D/BluetoothGatt(10377): registerApp()
07-01 11:53:22.833 D/BluetoothGatt(10377): registerApp() - UUID=fa5bce8a-416d-47fe-9a8a-e44156f7e865
07-01 11:53:22.834 D/BluetoothGatt(10377): onClientRegistered() - status=0 clientIf=6
07-01 11:53:24.622 D/BluetoothGatt(10377): onClientConnectionState() - status=133 clientIf=6 device=00:00:DE:AD:BE:EF
***** #4 Connection state changed to Disconnected with status 133.
***** #1 Disconnecting GATT
07-01 11:53:24.707 D/BluetoothGatt(10377): close()
07-01 11:53:24.707 D/BluetoothGatt(10377): unregisterApp() - mClientIf=6

如您所见,我与Bluetooth堆栈的所有交互都在主线程(#1)上进行.但是尽管如此,我在onClientConnectionState处理程序中仍收到状态133.

As you can see, all my interaction with the Bluetooth stack is occurring on the main thread (#1). But despite that, I'm receiving status 133 in my onClientConnectionState handler.

我的清单具有以下权限:

My manifest has these permissions:

  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

我正在使用最新的棉花糖工具进行编译,并以最低目标为4.0.3(API级别15)定位棉花糖.

I'm compiling with latest Marshmallow tooling, and am targeting Marshmallow with a minimum target of 4.0.3 (API level 15).

可能是什么原因造成的?

What might be causing this?

推荐答案

(注意:您可能已经在这样做,但是我对C#并不了解)

(Note: You may already be doing this, but I'm not well versed in C#)

根据我的经验,并不是真的只与主线程上的BLE设备进行交互,只是您不会一次向设备发送过多的请求.

In my experience, it hasn't really been that you just interact with the BLE device on the main thread, it's just that you don't flood the device with too many requests at once.

在Android上使用BLE时,我曾经遇到过这个问题(并阅读过有关使用主线程的类似评论),这是因为我向其中发布了过多的请求(读/写,通知/指示注册等)远程Gatt设备,然后再在BluetoothGattCallback对象中接收先前操作的回调.我设置了自己的托管gatt操作队列(一个线程阻塞,直到在GattCallback中接收到该操作的回调,或者初始读/写操作返回false,然后处理下一个排队的操作或使用退避乘数重试),而且由于我还没有遇到这个问题.据我所知,Android在排队"操作方面做得不好,因此"isBusy"布尔值在不知不觉中咬住了您(请注意BlueoothGattCharacteristic编写方法,如果这样做不会对您不利).我还注意到,您不想在回调对象中做很多工作,而是将回调委托给另一个线程或广播结果(这样就不会阻塞Binder线程).通常,我只是复制字节有效负载,然后将其传递给另一个HandlerThread进行解析.

I used to get this issue when working with BLE on Android (and read similar comments about using the main thread), and it was because I was posting too many requests (reads/writes, notification/indication registrations, etc) to the remote Gatt device before receiving callbacks for previous operations in the BluetoothGattCallback object. I set up my own managed gatt operation queue (a thread that blocks until a callback for that operation is received in the GattCallback, or the initial read/write operation returns false, then handles the next queued operation or retries with a backoff multiplier), and since I've not run into this issue. From what I can tell, Android doesn't do a good job of "queueing" operations, so the "isBusy" boolean bites you unknowingly (Look at the BlueoothGattCharacteristic write method if this doesn't jump out at you). I've also noticed that you don't want to do much work in your callback object, but delegate the callback to another thread or broadcast out the result (so you don't block the Binder thread). Normally I just copy the byte payload, and pass it off to another HandlerThread to parse.

此外,可以肯定的是,断开连接和关闭非常重要.我通常使用Service处理BLE交互,并在Service的onDestroy完成之前调用这两个交互.

Also, yeah, disconnecting and closing is pretty important for sure. I generally use a Service to handle BLE interactions and call both of these before the Service's onDestroy finishes.

这篇关于Android蓝牙错误133的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆