2015-04-21 289 views
0

我的Android应用程序仅适用于API Level 21,我正在Nexus 5上测试它。它是一个BLE中心,连接到一个BLE外设,在该BLE外设上我控制固件。Android BLE扫描SCAN_FAILED_ALREADY_STARTED并获取BluetoothDevice实例

使用startScan()首次扫描设备(外设)时,一切正常。假设我继续坚持传递给ScanCallback的BluetoothDevice实例。然后我可以调用connectGatt(),发现服务和读/写特征。到现在为止还挺好。

现在假设用户导航离开,时间流逝,然后他们回到应用程序,并希望做一些需要特征的东西。我现在已经退后一步,确保我有所有这些事情的一个非空实例:

BluetoothLeScanner 
BluetoothDevice 
BluetoothGatt 
BluetoothGattCharacteristic 

在这一点上,我BluetoothDevice类实例为null。没问题 - 我只需再次扫描并获取新实例。啊,但是现在我没有得到ScanCallback.onScanResult()呼吁在所有 - 我得到ScanCallback.onScanFailed()调用的错误代码

SCAN_FAILED_ALREADY_STARTED 

这是真实的,在BLE栈已经由以前的扫描和记忆拒绝复制它。但是,我现在如何从该扫描中获得BluetoothDevice实例?我没有办法在Level 21 API中做到这一点。

以下是我的BLE服务的完整代码,供各种活动使用。

/* Copyright (C) Eliot Stock - All Rights Reserved 
* Unauthorized copying of this file, via any medium is strictly prohibited. 
* Proprietary and confidential. 
*/ 
package com.eliotstock.bike.service; 

import android.app.Service; 
import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothGatt; 
import android.bluetooth.BluetoothGattCallback; 
import android.bluetooth.BluetoothGattCharacteristic; 
import android.bluetooth.BluetoothGattService; 
import android.bluetooth.BluetoothManager; 
import android.bluetooth.BluetoothProfile; 
import android.bluetooth.le.BluetoothLeScanner; 
import android.bluetooth.le.ScanCallback; 
import android.bluetooth.le.ScanFilter; 
import android.bluetooth.le.ScanResult; 
import android.bluetooth.le.ScanSettings; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.content.SharedPreferences; 
import android.os.Binder; 
import android.os.Handler; 
import android.os.IBinder; 
import android.os.Looper; 
import android.preference.PreferenceManager; 
import android.util.Log; 

import com.eliotstock.bike.ble.BleService; 
import com.eliotstock.bike.ble.Characteristic; 

import java.util.ArrayList; 
import java.util.List; 

public class BleServiceForSoPost extends Service { 

    private final String TAG = this.getClass().getSimpleName(); 

    private SharedPreferences sharedPreferences; 

    private String deviceMacAddress; 

    private BluetoothLeScanner bluetoothLeScanner; 
    private BluetoothDevice bleDevice; 
    private BluetoothGatt bleGatt; 

    private List<ScanFilter> scanFiltersFirstTime; 
    private List<ScanFilter> scanFiltersReconnect; 
    private ScanSettings scanSettingsLowPower; 
    private ScanSettings scanSettingsLowLatency; 

    private final IBinder binder = new BikeTrackerServiceBinder(); 

    private static final String PREF_DEVICE_MAC_ADDRESS = "pref_device_mac_address"; 

    private BluetoothGattCharacteristic bikeTrackerTestMode; 
    private BluetoothGattCharacteristic txPowerLevel; 

    private IntentFilter bondStateChangedFilter = 
      new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 

    private enum Action { 
     NONE, 
     READ_TEST_MODE, 
     WRITE_TEST_MODE 
    } 

    private Action action; 
    private Object actionValue; 
    private Boolean stopScanInProgress = false; 

    public class BikeTrackerServiceBinder extends Binder { 
     public BleServiceForSoPost getService() { 
      return BleServiceForSoPost.this; 
     } 
    } 

    public BleServiceForSoPost() { 
     Log.d(TAG, "Constructor " + this.hashCode()); 
    } 

    @Override 
    public void onCreate() { 
     Log.d(TAG, "onCreate() " + this.hashCode()); 

     action = Action.NONE; 
     actionValue = null; 

     sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
       getApplicationContext()); 
     deviceMacAddress = sharedPreferences.getString(PREF_DEVICE_MAC_ADDRESS, null); 

     final BluetoothManager bluetoothManager = 
       (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 
     final BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); 

     if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) { 
      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      enableBtIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      startActivity(enableBtIntent); 
      return; 
     } 

     bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); 

     Log.d(TAG, "Bonded devices (whether connected or not):"); 
     for (BluetoothDevice device : bluetoothAdapter.getBondedDevices()) { 
      Log.d(TAG, "* " + device.getName() + " (" + device.getAddress() + ")"); 
     } 

     ScanFilter scanFilterFirstTime = new ScanFilter.Builder() 
       .setDeviceName("Bike") 
       .build(); 
     scanFiltersFirstTime = new ArrayList<>(); 
     scanFiltersFirstTime.add(scanFilterFirstTime); 

     ScanFilter scanFilterReconnect = new ScanFilter.Builder() 
       .setDeviceAddress(deviceMacAddress) 
       .build(); 
     scanFiltersReconnect = new ArrayList<>(); 
     scanFiltersReconnect.add(scanFilterReconnect); 

     scanSettingsLowPower = new ScanSettings.Builder() 
       .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) 
       .build(); 

     scanSettingsLowLatency = new ScanSettings.Builder() 
       .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // High power for first scan only. 
       .build(); 

     if (deviceMacAddress == null) { 
      Log.d(TAG, "We do NOT know our device MAC address. Not scanning until prompted by" + 
        " user."); 
     } 
     else { 
      Log.d(TAG, "We know our device MAC address. Scanning only for it."); 

      bluetoothLeScanner.startScan(scanFiltersReconnect, scanSettingsLowPower, scanCallback); 
     } 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.d(TAG, "onStartCommand() " + this.hashCode()); 

     return START_STICKY; 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
     Log.d(TAG, "onBind() " + this.hashCode()); 

     return binder; 
    } 

    public void scanAndBindToNearestDevice() { 
     if (deviceMacAddress != null) { 
      return; 
     } 

     bluetoothLeScanner.startScan(scanFiltersFirstTime, scanSettingsLowLatency, scanCallback); 
    } 

    public void forgetDevice() { 
     SharedPreferences.Editor editor = sharedPreferences.edit(); 
     editor.putString(PREF_DEVICE_MAC_ADDRESS, deviceMacAddress); 
    } 

    @Override 
    public void onDestroy() { 
     Log.i(TAG, "onDestroy() " + this.hashCode()); 

     if (bleGatt == null) { 
      return; 
     } 

     Log.d(TAG, "Closing BluetoothGatt instance."); 
     bleGatt.close(); 
     bleGatt = null; 
    } 

    public void readTestMode() { 
     action = Action.READ_TEST_MODE; 

     reconnect(); 

     if (bikeTrackerTestMode == null) { 
      Log.e(TAG, "Trying to read test mode before we have a characteristic instance" + 
        " for it."); 
      return; 
     } 

     Log.d(TAG, "Reading characteristic for test mode."); 

     // Calls back to onCharacteristicRead(), which in turns calls back to 
     // SettingsActivity.setTestMode(). 
     if (!bleGatt.readCharacteristic(bikeTrackerTestMode)) { 
      Log.e(TAG, "Can't read test mode. BluetoothGatt.readCharacteristic() returned false."); 
     } 
    } 

    public void writeTestMode(Integer value) { 
     action = Action.WRITE_TEST_MODE; 
     actionValue = value; 

     reconnect(); 

     if (bikeTrackerTestMode == null) { 
      Log.e(TAG, "Trying to write test mode before we have a characteristic instance" + 
        " for it."); 
      return; 
     } 

     Log.d(TAG, "Writing characteristic for test mode."); 

     bikeTrackerTestMode.setValue(value, BluetoothGattCharacteristic.FORMAT_UINT8, 0); 

     if (!bleGatt.writeCharacteristic(bikeTrackerTestMode)) { 
      Log.e(TAG, "Can't write test mode. BluetoothGatt.writeCharacteristic() returned false."); 
     } 
    } 

    public Boolean isDeviceConnected() { 
     return (bleDevice != null && bleGatt != null && bikeTrackerTestMode != null); 
    } 

    // Check for null BLE Device, BLE GATT and BLE Characteristics, in that order, doing any 
    // scanning, connecting or bonding required to get back to a state where all three are 
    // available and we're bonded. 
    private void reconnect() { 
     if (bluetoothLeScanner == null) { 
      Log.w(TAG, "No BLE scanner instance available, probably because Bluetooth is turned" + 
        " off. Bailing out. Can't reconnect."); 
      return; 
     } 

     if (bleDevice == null) { 
      bluetoothLeScanner.startScan(scanFiltersFirstTime, scanSettingsLowLatency, scanCallback); 
      return; 
     } 

     if (bleGatt == null) { 
      bleDevice.connectGatt(BleServiceForSoPost.this, true, gattCallback); 
      return; 
     } 

     if (anyCharacteristicsAreNull()) { 
      if (!bleGatt.discoverServices()) { 
       Log.e(TAG, "Couldn't start discovering services." 
         + " BluetoothGatt.discoverServices() returned false. If this follows" 
         + " the status 133 problem with onConnectionStateChange(), reboot."); 
      } 
      return; 
     } 

     if (bleDevice.getBondState() != BluetoothDevice.BOND_BONDED) { 
      registerReceiver(bleBroadcastReceiver, bondStateChangedFilter); 

      if (!bleDevice.createBond()) { 
       Log.e(TAG, "Can't create bond. BluetoothDevice.createBond() returned false."); 
      } 
     } 

     Log.d(TAG, "Falling out of reconnect(). BLE device, GATT and characteristics are all ready" 
       + " and we're bonded."); 
    } 

    private final ScanCallback scanCallback = new ScanCallback() { 

     @Override 
     public void onBatchScanResults(List<ScanResult> results) { 
      for (ScanResult result : results) { 
       onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result); 
      } 
     } 

     public void onScanResult(int callbackType, ScanResult result) { 
      Log.i(TAG, "Advertisement: Device name: " + result.getDevice().getName() 
        + ", address: " + result.getDevice().getAddress() 
        + ", RSSI: " + result.getRssi()); 

      switch (result.getDevice().getBondState()) { 
       case BluetoothDevice.BOND_NONE: 
        Log.d(TAG, "Bond state: BOND_NONE"); 
        break; 

       case BluetoothDevice.BOND_BONDING: 
        Log.d(TAG, "Bond state: BOND_BONDING"); 
        break; 

       case BluetoothDevice.BOND_BONDED: 
        Log.d(TAG, "Bond state: BOND_BONDED"); 
        break; 
      } 

      if (stopScanInProgress) { 
       Log.d(TAG, "Dropping onScanResult() call while we're in the process of stopping" 
         + " scanning."); 
       return; 
      } 
      else { 
       Log.d(TAG, "Found device. Stopping scanning."); 
       stopScanInProgress = true; 
      } 

      bleDevice = result.getDevice(); 
      bluetoothLeScanner.stopScan(scanCallback); 

      if (deviceMacAddress != null) { 
       Log.d(TAG, "This is a reconnection. We already know our device's MAC address."); 

       if (!result.getDevice().getAddress().equals(deviceMacAddress)) { 
        Log.w(TAG, "We scanned for a known device MAC address (" + deviceMacAddress 
          + ") but got a scan result for a different one (" 
          + result.getDevice().getAddress() + "). This should never happen."); 
        return; 
       } 
      } 
      else { 
       Log.d(TAG, "This is a first connection. Storing device MAC address as shared" 
         + " preference."); 

       deviceMacAddress = result.getDevice().getAddress();    
       SharedPreferences.Editor editor = sharedPreferences.edit(); 
       editor.putString(PREF_DEVICE_MAC_ADDRESS, deviceMacAddress); 

       editor.apply(); 
      } 

      Log.d(TAG, "Connecting to GATT server."); 

      stopScanInProgress = false; 

      if (bleDevice == null) { 
       Log.wtf(TAG, "BLE Device is null in main looper thread." 
         + " Why? We should be calling connectGatt() now but can't."); 
       return; 
      } 

      bleDevice.connectGatt(BleServiceForSoPost.this, true, gattCallback); 
     } 

     @Override 
     public void onScanFailed(int errorCode) { 
      Log.w(TAG, "Scan failed."); 

      switch (errorCode) { 
       case SCAN_FAILED_ALREADY_STARTED: 
        Log.w(TAG, "Reason: 'Fails to start scan as BLE scan with the same settings" + 
          " is already started by the app.' Resuming reconnection from after" + 
          " scan. BLE device: " + bleDevice + ", BLE GATT: " + bleGatt); 
        break; 
       case SCAN_FAILED_APPLICATION_REGISTRATION_FAILED: 
        Log.w(TAG, "Reason: 'Fails to start scan as app cannot be registered.'"); 
        break; 
       case SCAN_FAILED_FEATURE_UNSUPPORTED: 
        Log.w(TAG, "Reason: 'Fails to start power optimized scan as this feature is not" 
          + " supported.'"); 
        break; 
       case SCAN_FAILED_INTERNAL_ERROR: 
        Log.w(TAG, "Reason: 'Fails to start scan due to an internal error.'"); 
        break; 
      } 

      bleDevice = null; 
     } 
    }; 

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { 
     @Override 
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
      Log.d(TAG, "onConnectionStateChange()"); 

      switch (status) { 
       case BluetoothGatt.GATT_SUCCESS: 
        Log.d(TAG, "Status: GATT_SUCCESS"); 
        break; 
       case BluetoothGatt.GATT_FAILURE: 
        Log.d(TAG, "Status: GATT_FAILURE"); 
        break; 
       case 8: 
        Log.d(TAG, "Status: 8. Normal if caused by peers moving apart."); 
        break; 
       case 22: 
        Log.d(TAG, "Status: 22. Don't know what this is but have seen it before."); 
        break; 
       case 34: 
        Log.d(TAG, "Status: 34. Don't know what this is but have seen it before."); 
        break; 
       case 133: 
        Log.e(TAG, "Status 133. This may mean the connection was lost because the" 
          + " remote device dropped it. See Android 4.4 bug."); 
        gatt.close(); 
        gatt.connect(); 
        break; 
       default: 
        Log.d(TAG, "Unrecognised status: " + status); 
      } 

      switch (newState) { 
       case BluetoothProfile.STATE_CONNECTED: 
        Log.d(TAG, "New state: STATE_CONNECTED");   
        break; 
       case BluetoothProfile.STATE_CONNECTING: 
        Log.d(TAG, "New state: STATE_CONNECTING");    
        break; 
       case BluetoothProfile.STATE_DISCONNECTED: 
        Log.d(TAG, "New state: STATE_DISCONNECTED");    
        break; 
       case BluetoothProfile.STATE_DISCONNECTING: 
        Log.d(TAG, "New state: STATE_DISCONNECTING");   
        break; 
       default: 
        Log.d(TAG, "Unrecognised new state: " + newState);     
      } 

      if (newState == BluetoothProfile.STATE_CONNECTED) { 
       Log.i(TAG, "CONNECTED to GATT server. Starting service discovery."); 

       bleGatt = gatt; 

       if (!gatt.discoverServices()) { 
        Log.e(TAG, "Couldn't start discovering services." 
          + " BluetoothGatt.discoverServices() returned false. If this follows" 
          + " the status 133 problem with onConnectionStateChange(), reboot."); 
       } 
      } 
      else if (newState == BluetoothProfile.STATE_DISCONNECTED) { 
       Log.i(TAG, "DISCONNECTED from GATT server."); 

       if (bleGatt != null) { 
        Log.d(TAG, "Closing BluetoothGatt instance."); 
        bleGatt.close(); 
       } 

       bleGatt = null; 
       bleDevice = null; 
       txPowerLevel = null; 

       if (deviceMacAddress == null) { 
        Log.wtf(TAG, "We've become disconnected but don't yet know our device MAC" 
          + " address, which should be impossible."); 
        return; 
       } 

       Log.d(TAG, "Waiting half a second..."); 

       new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 
        @Override 
        public void run() { 
         Log.d(TAG, "Starting scanning at low power, looking only for our known" + 
           " device."); 

         bluetoothLeScanner.startScan(scanFiltersReconnect, scanSettingsLowPower, 
           scanCallback); 
        } 
       }, 500); 
      } 
     } 

     @Override 
     public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
      if (status == BluetoothGatt.GATT_SUCCESS) { 
       Log.d(TAG, "Discovered services:"); 

       for (BluetoothGattService gattService : gatt.getServices()) { 
        Log.d(TAG, "*" + BleService.toDebugString(gattService)); 

        for (BluetoothGattCharacteristic c : gattService.getCharacteristics()) { 
         Log.d(TAG, "**" + Characteristic.toDebugString(c)); 

         if (Characteristic.BIKE_TRACKER_TEST_MODE_ID.equals(c.getUuid())) { 
          bikeTrackerTestMode = c; 
         } 

         if (Characteristic.TX_POWER_LEVEL.equals(c.getUuid())) { 
          txPowerLevel = c; 
         } 
        } 
       } 
      } 
      else if (status == 129) { 
       Log.w(TAG, "onServicesDiscovered received GATT_INTERNAL_ERROR"); 

       bikeTrackerTestMode = null; 
       txPowerLevel = null; 
      } 
      else { 
       Log.w(TAG, "onServicesDiscovered received non-GATT_SUCCESS status: " + status); 

       bikeTrackerTestMode = null; 
       txPowerLevel = null; 
      } 

      if (bleDevice == null) { 
       Log.wtf(TAG, "BluetoothDevice instance is null at service discovery. How did we" 
         + " get this far? Using the one on this GATT instance."); 
       bleDevice = gatt.getDevice(); 
      } 

      if (BluetoothDevice.BOND_NONE == bleDevice.getBondState()) { 
       Log.d(TAG, "Not yet bonded. Creating bond now."); 

       registerReceiver(bleBroadcastReceiver, bondStateChangedFilter); 

       if (!bleDevice.createBond()) { 
        Log.e(TAG, "Can't create bond. BluetoothDevice.createBond() returned false."); 
       } 

       return; 
      } 
      else { 
       Log.d(TAG, "Bonded (or bonding) already. Good."); 
      } 

      if (bleGatt == null) { 
       Log.w(TAG, "We have no BluetoothGatt instance and should do by now. Bailing out of" 
         + " doing anything with Characteristics."); 
       return; 
      } 

      if (action == Action.READ_TEST_MODE) { 
       Log.d(TAG, "Reading characteristic for test Mode."); 

       if (!bleGatt.readCharacteristic(bikeTrackerTestMode)) { 
        Log.e(TAG, "Can't read test mode. BluetoothGatt.readCharacteristic()" + 
          " returned false."); 
       } 
      } 

      if (action == Action.WRITE_TEST_MODE) { 
       Log.d(TAG, "Writing characteristic for test mode."); 

       Integer value = (Integer)actionValue; 
       bikeTrackerTestMode.setValue(value, BluetoothGattCharacteristic.FORMAT_UINT8, 0); 

       if (!bleGatt.writeCharacteristic(bikeTrackerTestMode)) { 
        Log.e(TAG, "Can't write test mode. BluetoothGatt.writeCharacteristic()" + 
          " returned false."); 
       } 

       actionValue = null; 
      } 
     } 

     @Override 
     public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic c, 
       int status) { 
      Log.d(TAG, "onCharacteristicRead(): " + Characteristic.toDebugString(c)); 

      onCharacteristicReadOrChanged(c, status); 
     } 

     @Override 
     public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic c) { 
      Log.d(TAG, "onCharacteristicChanged(): " + Characteristic.toDebugString(c)); 

      onCharacteristicReadOrChanged(c, 0); 
     } 

     private void onCharacteristicReadOrChanged(BluetoothGattCharacteristic c, int status) { 
      if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { 
       Log.w(TAG, "Got GATT_INSUFFICIENT_AUTHENTICATION status. Are we bonded?"); 
       return; 
      } 
      else if (status == 132) { 
       Log.w(TAG, "Got non-GATT_SUCCESS status of 132. All bets off below."); 
      } 
      else if (status == 133) { 
       Log.w(TAG, "Got non-GATT_SUCCESS status of 133. All bets off below."); 
      } 
      else if (status != BluetoothGatt.GATT_SUCCESS) { 
       Log.w(TAG, "Got non-GATT_SUCCESS status of " + status + ". All bets off below."); 
      } 

      if (bikeTrackerTestMode.equals(c)) { 
       try { 
        Integer testModeInt = c.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 
          0); 

        Log.d(TAG, "Bike Tracker test mode: " + testModeInt); 
       } 
       catch (NullPointerException e) { 
        Log.w(TAG, "Can't really read test mode characteristic. Value is null."); 
       } 
      } 
      else if (txPowerLevel.equals(c)) { 
       Log.d(TAG, "Tx Power Level: " + new String(c.getValue())); 
      } 
      else { 
       Log.w(TAG, "Unrecognised characteristic read or changed: " + c); 
      } 

      action = null; 
     } 

     @Override 
     public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic c, 
       int status) { 
      Log.d(TAG, "onCharacteristicWrite(): " + Characteristic.toDebugString(c)); 

      if (BluetoothGatt.GATT_SUCCESS == status) { 
       Log.d(TAG, "Success"); 
      } 
      else { 
       Log.e(TAG, "Error writing characteristic. Status: " + status); 
      } 
     } 

     @Override 
     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 
     } 
    }; 

    private final BroadcastReceiver bleBroadcastReceiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      Log.d(TAG, "onReceive(): " + intent.getAction()); 

      if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { 
       final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); 
       final int previousBondState = 
         intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); 

       if (previousBondState != BluetoothDevice.BOND_BONDED 
         && bondState == BluetoothDevice.BOND_BONDED) { 
        Log.d(TAG, "Bonded. Unregistering broadcast receiver."); 
        unregisterReceiver(this); 

        if (bleGatt == null) { 
         Log.w(TAG, "Can't read sensitivity. BluetoothGatt is still null."); 
         return; 
        } 

        Log.d(TAG, "Reading characteristic for test mode."); 

        if (!bleGatt.readCharacteristic(bikeTrackerTestMode)) { 
         Log.e(TAG, "Can't read test mode. BluetoothGatt.readCharacteristic()" + 
           " returned false."); 
        } 
       } 
       else if (previousBondState == BluetoothDevice.BOND_BONDED 
         && bondState != BluetoothDevice.BOND_BONDED) { 
        Log.d(TAG, "Unbonded."); 
       } 
      } 
      else { 
       Log.d(TAG, "Ignoring BLE irrelevant broadcast intent: " + intent.getAction()); 
      } 
     } 
    }; 

    private Boolean anyCharacteristicsAreNull() { 
     if (bikeTrackerTestMode == null 
      || txPowerLevel == null) { 
      return true; 
     } 

     return false; 
    } 

} 
+0

我要指出,我BluetoothGatt实例也为空,所以没有跳过BluetoothDevice.connectGatt()调用和直行到BluetoothGatt.discoverServices()。 – Eliot

+0

你使用的是什么代码? –

+0

公平的评论。已添加完整的代码。 – Eliot

回答

-1

试试这个:

bluetoothLeScanner.stopScan(scanCallback); 

变化

bluetoothLeScanner.stopScan(this); 
+0

这是有效的,但我仍然获得SCAN_FAILED_ALREADY_STARTED扫描,我已经据说停止了stopScan()。 – Eliot