12

我目前有一种写入BLE设备的方法来发出哔哔声。我的蓝牙回调去如下:BLUetooth Gatt Callback不适用于棒棒糖的新API

ReadCharacteristic rc = new ReadCharacteristic(context, ds.getMacAddress(), serviceUUID, UUID.fromString(myUUID), "") { 
       @Override 
       public void onRead() { 
        Log.w(TAG, "callDevice onRead"); 
        try{Thread.sleep(1000);}catch(InterruptedException ex){} 
        WriteCharacteristic wc = new WriteCharacteristic(activity, context, getMacAddress(), serviceUUID, UUID.fromString(myUUID), ""){ 
         @Override 
         public void onWrite(){ 
          Log.w(TAG, "callDevice onWrite"); 
         } 
         @Override 
         public void onError(){ 
          Log.w(TAG, "callDevice onWrite-onError"); 
         } 
        }; 

//     Store data in writeBuffer 
        wc.writeCharacteristic(writeBuffer); 
       } 

       @Override 
       public void onError(){ 
        Log.w(TAG, "callDevice onRead-onError"); 
       } 
      }; 

      rc.readCharacteristic(); 

我ReadCharacteristic实现如下:

public class ReadCharacteristic extends BluetoothGattCallback { 
    public ReadCharacteristic(Context context, String macAddress, UUID service, UUID characteristic, Object tag) { 
     mMacAddress = macAddress; 
     mService = service; 
     mCharacteristic = characteristic; 
     mTag = tag; 
     mContext = context; 
     this.activity =activity; 
     final BluetoothManager bluetoothManager = 
       (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); 
     mBluetoothAdapter = bluetoothManager.getAdapter(); 

    } 

    final private static String TAG = "ReadCharacteristic"; 
    private Object mTag; 
    private String mMacAddress; 
    private UUID mService; 
    private UUID mCharacteristic; 
    private byte[] mValue; 
    private Activity activity; 
    private BluetoothAdapter mBluetoothAdapter; 
    private Context mContext; 

    private int retry = 5; 


    public String getMacAddress() { 
     return mMacAddress; 
    } 

    public UUID getService() { 
     return mService; 
    } 

    public UUID getCharacteristic() { 
     return mCharacteristic; 
    } 

    public byte[] getValue() { return mValue; } 

    public void onRead() { 
     Log.w(TAG, "onRead: " + getDataHex(getValue())); 
    } 

    public void onError() { 
     Log.w(TAG, "onError"); 
    } 

    public void readCharacteristic(){ 
     if (retry == 0) 
     { 
      onError(); 
      return; 
     } 
     retry--; 



       final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(getMacAddress()); 
       if (device != null) { 
        Log.w(TAG, "Starting Read [" + getService() + "|" + getCharacteristic() + "]"); 
        final ReadCharacteristic rc = ReadCharacteristic.this; 
        device.connectGatt(mContext, false, rc); 
       } 

    } 

    @Override 
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
     Log.w(TAG,"onConnectionStateChange [" + status + "|" + newState + "]"); 
     if ((newState == 2)&&(status ==0)) { 
      gatt.discoverServices(); 
     } 

     else{ 
      Log.w(TAG, "[" + status + "]"); 
     // gatt.disconnect(); 
      gatt.close(); 
      try 
      { 
       Thread.sleep(2000); 
      } 
      catch(Exception e) 
      { 

      } 
      readCharacteristic(); 
     } 
    } 

    @Override 
    public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
     Log.w(TAG,"onServicesDiscovered [" + status + "]"); 
     BluetoothGattService bgs = gatt.getService(getService()); 
     if (bgs != null) { 
      BluetoothGattCharacteristic bgc = bgs.getCharacteristic(getCharacteristic()); 
      gatt.readCharacteristic(bgc); 
     } 
    } 

    @Override 
    public void onCharacteristicRead(BluetoothGatt gatt, 
            BluetoothGattCharacteristic characteristic, 
            int status) { 
     Log.w(TAG,"onCharacteristicRead [" + status + "]"); 
     if (status == BluetoothGatt.GATT_SUCCESS) { 
      mValue = characteristic.getValue(); 
      Log.w(TAG,"onCharacteristicRead [" + mValue + "]"); 
      gatt.disconnect(); 
      gatt.close(); 
      onRead(); 
     } 

     else { 
      gatt.disconnect(); 
      gatt.close(); 
     } 
    } 


} 

这个当前方法工作​​完全正常运行奇巧及以下的设备。但是当我在棒棒糖上运行相同的功能时,它会发出几次蜂鸣声,然后停止工作。从那时起,无论何时我尝试连接,它都表示设备已断开连接,并在OnConnectionStateChanged方法中给我提供了257的错误代码。

每当我调用这个方法我也得到这个错误 -

04-20 14:14:23.503 12329-12384/com.webble.xy W/BluetoothGatt﹕ Unhandled exception in callback 
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.BluetoothGattCallback.onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)' on a null object reference 
      at android.bluetooth.BluetoothGatt$1.onClientConnectionState(BluetoothGatt.java:181) 
      at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:70) 
      at android.os.Binder.execTransact(Binder.java:446) 

有谁也面临同样的问题的人?当我尝试调试时,我从来没有遇到该对象为null。

+0

我的应用程序在> = 5.0时出现同样的问题。你身边没有新东西吗? – Hrk

+3

我刚才发现这个错误发生在我调用disconnect并紧接着关闭时,因为在调用disconnect之前onConnectionStateChange对象被设置为null。当我打电话时,这个错误不会显示出来。但是这并没有解决问题。我仍然试图在这个问题上打破我的头脑。当我重新启动蓝牙时,它再次开始工作,但这个问题在一段时间后仍然存在。请让我知道,如果你找到任何解决方案 –

回答

-1

感谢您指出问题Shashank。

我已经看过Google example,并遵循他们的建议,它像我的设备的魅力。

您应该在onUnbind中调用close()函数,需要时调用disconnect()函数,例如,当您退出应用程序时。

7

该问题已向Google报告为Issue 183108: NullPointerException in BluetoothGatt.java when disconnecting and closing

一种解决方法是调用disconnect()当你想关闭BLE连接 - 然后只调用close()onConnectionStateChange回调:

public void shutdown() { 
    try { 
     mBluetoothGatt.disconnect(); 
    } catch (Exception e) { 
     Log.d(TAG, "disconnect ignoring: " + e); 
    } 
    } 

    private final BluetoothGattCallback mGattCallback = 
    new BluetoothGattCallback() { 
    @Override 
     public void onConnectionStateChange(BluetoothGatt gatt, 
     int status, int newState) { 
     if (newState == BluetoothProfile.STATE_CONNECTED) { 

     } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { 

      try { 
      gatt.close(); 
      } catch (Exception e) { 
      Log.d(TAG, "close ignoring: " + e); 
      } 
     } 
     } 

这里是我的全部源代码(A类做正常的扫描,直接扫描 - 和发现服务):

public class BleObject { 

    public static final String ACTION_BLUETOOTH_ENABLED = "action.bluetooth.enabled"; 
    public static final String ACTION_BLUETOOTH_DISABLED = "action.bluetooth.disabled"; 
    public static final String ACTION_DEVICE_FOUND  = "action.device.found"; 
    public static final String ACTION_DEVICE_BONDED  = "action.device.bonded"; 
    public static final String ACTION_DEVICE_CONNECTED = "action.device.connected"; 
    public static final String ACTION_DEVICE_DISCONNECTED = "action.device.disconnected"; 
    public static final String ACTION_POSITION_READ  = "action.position.read"; 

    public static final String EXTRA_BLUETOOTH_DEVICE  = "extra.bluetooth.device"; 
    public static final String EXTRA_BLUETOOTH_RSSI  = "extra.bluetooth.rssi"; 

    private Context mContext; 
    private IntentFilter mIntentFilter; 
    private LocalBroadcastManager mBroadcastManager; 
    private BluetoothAdapter mBluetoothAdapter; 
    private BluetoothGatt mBluetoothGatt; 
    private BluetoothLeScanner mScanner; 
    private ScanSettings mSettings; 
    private List<ScanFilter> mScanFilters; 

    private Handler mConnectHandler; 

    public BleObject(Context context) { 
    mContext = context; 

    if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 
     Log.d(TAG, "BLE not supported"); 
     return; 
    } 

    BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); 
    mBluetoothAdapter = bluetoothManager.getAdapter(); 
    if (mBluetoothAdapter == null) { 
     Log.d(TAG, "BLE not accessible"); 
     return; 
    } 

    mIntentFilter = new IntentFilter(); 
    mIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 
    mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 

    mSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); 
    mScanFilters = new ArrayList<ScanFilter>(); 

    mConnectHandler = new Handler(); 

    mBroadcastManager = LocalBroadcastManager.getInstance(context); 
    } 

    public boolean isEnabled() { 
    return (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()); 
    } 

    private ScanCallback mScanCallback = new ScanCallback() { 
    @Override 
     public void onScanResult(int callbackType, ScanResult result) { 
     processResult(result); 
     } 

    @Override 
     public void onBatchScanResults(List<ScanResult> results) { 
     for (ScanResult result: results) { 
      processResult(result); 
     } 
     } 

    private void processResult(ScanResult result) { 
     if (result == null) 
     return; 

     BluetoothDevice device = result.getDevice(); 
     if (device == null) 
     return; 

     Intent i = new Intent(Utils.ACTION_DEVICE_FOUND); 
     i.putExtra(Utils.EXTRA_BLUETOOTH_DEVICE, device); 
     i.putExtra(Utils.EXTRA_BLUETOOTH_RSSI, result.getRssi()); 
     mBroadcastManager.sendBroadcast(i); 
    } 
    }; 

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { 
    @Override 
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
     if (newState == BluetoothProfile.STATE_CONNECTED) { 
      if (gatt == null) 
      return; 

      BluetoothDevice device = gatt.getDevice(); 
      if (device == null) 
      return; 

      Log.d(TAG, "BluetoothProfile.STATE_CONNECTED: " + device); 
      Intent i = new Intent(Utils.ACTION_DEVICE_CONNECTED); 
      i.putExtra(Utils.EXTRA_BLUETOOTH_DEVICE, device); 
      mBroadcastManager.sendBroadcast(i); 

     } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { 

      Log.d(TAG, "BluetoothProfile.STATE_DISCONNECTED"); 
      Intent i = new Intent(Utils.ACTION_DEVICE_DISCONNECTED); 
      mBroadcastManager.sendBroadcast(i); 

      // Issue 183108: https://code.google.com/p/android/issues/detail?id=183108 
      try { 
      gatt.close(); 
      } catch (Exception e) { 
      Log.d(TAG, "close ignoring: " + e); 
      } 
     } 
     } 

    @Override 
     public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
     if (gatt == null) 
      return; 

     for (BluetoothGattService service: gatt.getServices()) { 
      Log.d(TAG, "service: " + service.getUuid()); 

      for (BluetoothGattCharacteristic chr: service.getCharacteristics()) { 
      Log.d(TAG, "char: " + chr.getUuid()); 
      } 
     } 
     } 
    }; 

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 
    public void onReceive(Context context, Intent intent) { 
     final String action = intent.getAction(); 

     if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { 
     final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 

     switch (state) { 
      case BluetoothAdapter.STATE_TURNING_OFF: { 
                Log.d(TAG, "BluetoothAdapter.STATE_TURNING_OFF"); 
                break; 
                } 
      case BluetoothAdapter.STATE_OFF: { 
              Log.d(TAG, "BluetoothAdapter.STATE_OFF"); 
              Intent i = new Intent(Utils.ACTION_BLUETOOTH_DISABLED); 
              mBroadcastManager.sendBroadcast(i); 
              break; 
              } 
      case BluetoothAdapter.STATE_TURNING_ON: { 
                Log.d(TAG, "BluetoothAdapter.STATE_TURNING_ON"); 
                break; 
                } 
      case BluetoothAdapter.STATE_ON: { 
              Log.d(TAG, "BluetoothAdapter.STATE_ON"); 
              Intent i = new Intent(Utils.ACTION_BLUETOOTH_ENABLED); 
              mBroadcastManager.sendBroadcast(i); 
              break; 
              } 
     } 
     } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { 
     final int state  = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); 
     final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR); 

     if (state == BluetoothDevice.BOND_BONDED && 
      prevState == BluetoothDevice.BOND_BONDING) { 

      if (mBluetoothGatt != null) { 
      BluetoothDevice device = mBluetoothGatt.getDevice(); 
      if (device == null) 
       return; 

      Intent i = new Intent(Utils.ACTION_DEVICE_BONDED); 
      i.putExtra(Utils.EXTRA_BLUETOOTH_DEVICE, device); 
      mBroadcastManager.sendBroadcast(i); 
      } 
     } 
     } 
    } 
    }; 

    // scan for all BLE devices nearby 
    public void startScanning() { 
    Log.d(TAG, "startScanning"); 

    mScanFilters.clear(); 
    // create the scanner here, rather than in init() - 
    // because otherwise app crashes when Bluetooth is switched on 
    mScanner = mBluetoothAdapter.getBluetoothLeScanner(); 
    mScanner.startScan(mScanFilters, mSettings, mScanCallback); 
    } 

    // scan for a certain BLE device and after delay 
    public void startScanning(final String address) { 
    Log.d(TAG, "startScanning for " + address); 

    mScanFilters.clear(); 
    mScanFilters.add(new ScanFilter.Builder().setDeviceAddress(address).build()); 
    // create the scanner here, rather than in init() - 
    // because otherwise app crashes when Bluetooth is switched on 
    mScanner = mBluetoothAdapter.getBluetoothLeScanner(); 
    mScanner.startScan(mScanFilters, mSettings, mScanCallback); 
    } 

    public void stopScanning() { 
    Log.d(TAG, "stopScanning"); 

    if (mScanner != null) { 
     mScanner.stopScan(mScanCallback); 
     mScanner = null; 
    } 

    mScanFilters.clear(); 
    } 

    public void connect(final BluetoothDevice device) { 
    Log.d(TAG, "connect: " + device.getAddress() + ", mBluetoothGatt: " + mBluetoothGatt); 

    mConnectHandler.post(new Runnable() { 
     @Override 
     public void run() { 
     setPin(device, Utils.PIN); 
     mBluetoothGatt = device.connectGatt(mContext, true, mGattCallback); 
     } 
     }); 
    } 

    private void setPin(BluetoothDevice device, String pin) { 
    if (device == null || pin == null || pin.length() < 4) 
     return; 

    try { 
     device.setPin(pin.getBytes("UTF8")); 
    } catch (Exception e) { 
     Utils.logw("setPin ignoring: " + e); 
    } 
    } 

    // called on successful device connection and will toggle reading coordinates 
    public void discoverServices() { 
    if (mBluetoothGatt != null) 
     mBluetoothGatt.discoverServices(); 
    } 

    public boolean isBonded(BluetoothDevice device) { 
    Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices(); 
    if (bondedDevices == null || bondedDevices.size() == 0) 
     return false; 

    for (BluetoothDevice bondedDevice: bondedDevices) { 
     Log.d(TAG, "isBonded bondedDevice: " + bondedDevice); 

     if (bondedDevice.equals(device)) { 
     Log.d(TAG, "Found bonded device: " + device); 
     return true; 
     } 
    } 

    return false; 
    } 

    public void startup() { 
    try { 
     mContext.registerReceiver(mReceiver, mIntentFilter); 
    } catch (Exception e) { 
     Log.d(TAG, "registerReceiver ignoring: " + e); 
    } 
    } 

    public void shutdown() { 
    Log.d(TAG, "BleObject shutdown"); 

    try { 
     mContext.unregisterReceiver(mReceiver); 
    } catch (Exception e) { 
     Log.d(TAG, "unregisterReceiver ignoring: " + e); 
    } 

    try { 
     stopScanning(); 
    } catch (Exception e) { 
     Log.d(TAG, "stopScanning ignoring: " + e); 
    } 

    try { 
     mBluetoothGatt.disconnect(); 
    } catch (Exception e) { 
     Log.d(TAG, "disconnect ignoring: " + e); 
    } 

    mConnectHandler.removeCallbacksAndMessages(null); 
    } 
} 

在它通过LocalBroadcastManager广播意图每个BLE事件。

+0

有没有任何保证调用disconnect()将导致onConnectionStateChange(...,newState = BluetoothProfile.STATE_DISCONNECTED)被调用? – swooby

相关问题