Android how to read multiple BLE characteristics with a PriorityQueue

Thanks a lot for your post, Robert K. I wanted my app to read all the characteristic values by itself and show the characteristic value in the ExpandableList instead of the UUID. Robert K's code worked for me but I have experienced an offset of the values that were being displayed. So I made some slight changes and want to share it: 1.

  1. This is how I modified onServicesDiscovered and OnCharacteristicRead:

        public List<BluetoothGattCharacteristic> chars = new ArrayList<>();
    
    public void requestCharacteristics(BluetoothGatt gatt) {
            gatt.readCharacteristic(chars.get(chars.size() - 1));
    }
    
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
            List<BluetoothGattService> services = gatt.getServices();
            for(BluetoothGattService service:services){
                chars.addAll(service.getCharacteristics());
            }
            requestCharacteristics(gatt);
        } else {
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }
    
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            chars.remove(chars.get(chars.size() - 1));
            if (chars.size() > 0) {
                requestCharacteristics(gatt);
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            } else {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            }
        }
    }
    
  2. the introduced List of characteristics is emptied after each disconnection.

  3. I introduced a list to save the characteristic values and an integer showing which index I am at (these need to be emptied / set to zero after each disconnection). I modified the displayData method, which is called after each characteristicRead:

public

public List<String> mCharValues = new ArrayList<>();
public int idx_charValues = 0;
private void displayData(String data) {
    if (data != null) { mCharValues.add(0, data); }
    else { mCharValues.add(0, "no Data"); }
}
  1. I want the characteristic values to be displayed on the ExpandableList as soon as services are discovered. The method displayGattServices fills the ExpandableList with the services' and characteristics' names and UUIDs.

Instead of filling the UUID, I fill the corresponding element of mCharValues

currentCharaData.put(LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString));
currentCharaData.put(LIST_UUID, mCharValues.get(idx_charValues));
idx_charValues = idx_charValues+1;
gattCharacteristicGroupData.add(currentCharaData);
  1. Finally, I commented out the content of the ExpandableListView.OnChildClickListener. Apart from what I introduced here I left the rest of the code pretty much the same.

To anyone who might encounter the same problem, here is an easy solution using a List<> of characteristics.

public static final BluetoothGattCallback readGattCallback = new BluetoothGattCallback() {

    List<BluetoothGattCharacteristic> chars = new ArrayList<>();

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

        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Log.v(TAG, "Connected!");
            broadcastingInterval = 999;
            transmissionPower = 999;
            gatt.discoverServices();
        }
        if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.v(TAG, "Disconnected...");

        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {

        List<BluetoothGattService> services = gatt.getServices();
        BluetoothGattService rightService = null;

        for (int i = 0; i < services.size(); i++) {
            if (services.get(i).getCharacteristics().size() > 8) {
                rightService = services.get(i);
            }
        }

        chars.add(rightService.getCharacteristics().get(4));
        chars.add(rightService.getCharacteristics().get(6));

        requestCharacteristics(gatt);

    }

    public void requestCharacteristics(BluetoothGatt gatt) {
        gatt.readCharacteristic(chars.get(chars.size()-1));
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {

            if (characteristic.getUuid().toString().substring(7, 8).equals("5")) {
                transmissionPower = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                Log.v(TAG, "tPOWER READ");

            } else if (characteristic.getUuid().toString().substring(7,8).equals("7")) {
                broadcastingInterval = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                Log.v(TAG, "INTERVAL READ");
            }

            chars.remove(chars.get(chars.size() - 1));

            if (chars.size() > 0) {
                requestCharacteristics(gatt);
            } else {
                gatt.disconnect();
            }
        }
    }

};
  1. Create a list of characteristics
  2. In onServicesDiscovered populate the list with characteristics you want to read/write
  3. Create a new method called requestCharacteristics(gatt) and pass the gatt object to it. Call this method from onServicesDiscovered after adding characteristics to the list.
  4. In requestCharacteristics() method call gatt.readCharacteristic(chars.get(chars.size()-1));
  5. In onCharacteristicRead check if size of your list is not zero, then read your characteristic, remove the last item of your list and call requestCharacteristic() again.
  6. That's all