2016-07-01 2 views
4

Android에서 블루투스 장치에 연결하려고합니다. 내 onClientConnectionState 처리기에 상태 133이 전송됩니다. 항상이 오류가 발생하는 것은 아닙니다. 때로는 제대로 연결됩니다. 나는 문제를 일으키는 것에 손가락을 대지 못했습니다. 장치 및 내 repro 응용 프로그램을 다시 시작한 후 즉시 그것을했습니다.Android 블루투스 오류 133

  • 하는 닫아야합니다 모든 BT API를위한 UI 스레드를 사용

    나는 (here, herehere에서) 몇 가지 질문 알고 있어요 포함하여,이 문제에 대한 해결책을 제시 GATT가 완료되면

그러나 나는 그것을 모두하고있다. 또한 내 기기는 Nexus 5 (Lollipop을 실행 중)인데, 일부 사용자는 BT 상호 작용이 UI 스레드에 있어야하지 않아야합니다.

나는 가능한 가장 간단한 repro을 조립했습니다. 그것은 C#에서의하지만 자바 상당 명백해야한다 :

[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); 
     } 
    } 
} 

그리고 여기에 (내가 너무 안드로이드의 BluetoothGatt 소스의 출력에 남아있는 것)이 실행의 출력을 : 당신이 할 수

***** #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 

모든 블루투스 스택과의 상호 작용은 메인 스레드 (# 1)에서 발생합니다. 그럼에도 불구하고 내 onClientConnectionState 처리기에서 상태 133을받습니다.

내 매니페스트는 이러한 권한이 : 나는 최신 마시 멜로 도구를 사용하여 컴파일하고있어, 및 4.0.3의 최소 목표 (API 레벨 15)와 산들을 목표로하고

<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" /> 

.

이 문제의 원인은 무엇입니까?

+1

매니페스트 파일에 어떤 권한이 있는지 알려줄 수 있습니까? 또한 연결을 시도하기 전에 검사를 중지 할 수 있습니까? – Zomb

+0

^^ 정지 검색 제안에 대해 ^^ upvoted, 그 것을 알지 못했습니다 – Submersed

+0

@Zomb 내 질문에 대한 자세한 내용을 추가했습니다. 그것은 분명히 오늘 아침에 나를 위해 잘 작동하지만, 다음에 팝업 트릭을 멈추도록 시도해야 할 것입니다. –

답변

2

(참고 : 당신은 이미이 일을 할 수있다,하지만 난 잘 C#으로 조예가 아니에요)

내 경험에

, 정말 그냥 메인 스레드에서 BLE 장치와 상호 작용하지 않았다 한 번에 너무 많은 요청을 장치에 범람하지 않는 것입니다.

안드로이드에서 BLE로 작업 할 때 (그리고 메인 쓰레드 사용에 관한 비슷한 의견을 읽었을 때)이 문제를 겪었는데, 너무 많은 요청 (읽기/쓰기, 알림/표시 등록 등) BluetoothGattCallback 객체에서 이전 작업에 대한 콜백을 수신하기 전에 원격 Gatt 장치에 연결합니다. 나 자신의 managed gatt operation queue (GattCallback에서 해당 작업에 대한 콜백이 수신 될 때까지 차단되는 스레드 또는 초기 읽기/쓰기 작업이 false를 반환 한 다음 대기열에있는 다음 작업을 처리하거나 백 오프 멀티 플라이어로 재 시도하는 스레드)를 설정합니다. 그리고 나는이 문제를 다루지 않았기 때문에. 내가 말할 수있는 것부터 안드로이드는 "큐잉"작업을 훌륭히 수행하지 못하기 때문에 "isBusy"부울이 모르는 사이에 물었다. (BlueoothGattCharacteristic write 메소드를 보자. 또한 콜백 객체에서 많은 작업을 수행하고 싶지 않지만 콜백을 다른 스레드에 위임하거나 결과를 브로드 캐스팅하여 (바인더 스레드를 차단하지 않도록)주의를 기울였습니다. 일반적으로 바이트 페이로드를 복사 한 다음 다른 HandlerThread로 전달하여 구문 분석합니다.

또한 예, 연결 해제 및 닫기는 확실히 중요합니다.나는 일반적으로 서비스를 사용하여 BLE 상호 작용을 처리하고 서비스의 onDestroy가 끝나기 전에이 두 가지를 호출합니다.

+0

실제 구현에 이미 작업 대기열이 있지만 위의 테스트 응용 프로그램에서 볼 수 있듯이 그렇게까지 멀지는 않습니다. 나는 연결을 설정하는 첫 번째 장애물 (종종, 항상은 아니지만)에 실패하고 있습니다. –

+0

또한이 결과는 항상 얻었습니까? 또는 성공적인 연결을 얻었습니까? – Submersed

+0

죄송합니다. 잠깐만 요. 흥미 롭 군. 어떤 펌웨어? – Submersed