Animesh Jena
Animesh Jena

Reputation: 1551

onCharacteristicChanged() been called multiple times

I am working with BLE connection in my app. I have a single class for the bluetooth functionalities and I am passing a command from a different fragment class for writing any value.

So based on the scenario, inside the fragment, on click of a button will send a write command to the bluetooth class. Its working fine in the first time and I am getting the response. But while clicking the button the button for the second time, onCharacteristicChanged() is called twice and the third time click makes it being called thrice and so on. I genuinely can't figure it out. I will post my code below. Please have a look. In case of any queries, please do let me know. Thanks in advance.

I am writing data inside the OnDescriptorWrite() where as recieving data inside onCharacteristicChanged().

Inside the fragment:

     rvw_availableList.addOnItemTouchListener((
                new RecyclerItemClickListener(myContext, new RecyclerItemClickListener.OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, int position)
                    {
                      BluetoothDevice bl_device = al_deviceList.get(position);
                      bleUtil.writeData(bl_device,"3AxxxxxxD");
                    }
                })
        ));

Now inside the writeData() of BleUtil Class:

    public void writeData(BluetoothDevice bluetoothDevice, final String value)
    {
        BluetoothGattCallback gattCallback =
                new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                        gatt.discoverServices();

                    }

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


                        activity.runOnUiThread(new Runnable() {
                            public void run() {

                               // prgd_progress.HideProgressDialog();
                                Log.d("onServicesDiscovered", "Service uuid ");

                                List<BluetoothGattService> gattServices = gatt.getServices();


                                Log.d("onServicesDiscovered", "Services count: "+gattServices.size());

                                for (BluetoothGattService gattService: gattServices)
                                {
                                    Log.d("aniservice",gattService.getUuid().toString());
                                }

                                if (status == BluetoothGatt.GATT_SUCCESS) {

                                    ArrayList<String> alst_uuid = new ArrayList<String>();


                                    BluetoothGattCharacteristic characteristic =
                                            gatt.getService(UUID.fromString(SERVICE_ID)).getCharacteristics().get(0);
                                    Log.d("anicheck",characteristic.getUuid().toString());
                                    Log.d("anicheck",characteristic.getDescriptors().get(0).getUuid().toString());
//                                    BluetoothGattCharacteristic characteristic =
//                                           gattServices.get(0).getCharacteristics().get(0);

                                    //        Log.d("foundoutchar",gattServices.get(0).getUuid()+"  "+gattServices.get(0).getCharacteristics().get(0).getUuid()+"");
                                    gatt.setCharacteristicNotification(characteristic,true);

                                    for (BluetoothGattDescriptor descriptor:characteristic.getDescriptors()){
                                        Log.e("anicheck", "BluetoothGattDescriptor: "+descriptor.getUuid().toString());
                                    }
                                    final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

                                    if(descriptor!= null)
                                    {
                                        descriptor.setValue(
                                                BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                                        gatt.writeDescriptor(descriptor);

                                    }
                                    else
                                    {
                                        Toast.makeText(activity,"nullval", Toast.LENGTH_SHORT).show();
                                    }

//                                    Log.d("foundoutchar", descriptor.getUuid().toString());


                                }
                            }
                        });


                    }

                    @Override
                    public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
                        super.onCharacteristicWrite(gatt, characteristic, status);
                        activity.runOnUiThread(new Runnable() {
                            public void run()
                            {

                            }
                        });
                    }

                    @Override
                    public void onCharacteristicRead(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status)
                    {
                        Log.d("onCharacteristicread",characteristic.getValue().toString());
                        Log.d("onCharacteristicread","called");


                    }

                    @Override
                    public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
                        super.onCharacteristicChanged(gatt, characteristic);
                        byte[] charValue = characteristic.getValue();
                        final String str_result = bytesToHex(charValue);
                        Log.d("onCharacteristicfullres",str_result);
                        final Intent intent = new Intent("ble_data"); //FILTER is a string to identify this intent
                        intent.putExtra("val", "getdeviceinfo");
                        intent.putExtra("data", str_result);
                        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);




                        activity.runOnUiThread(new Runnable() {
                            public void run()
                            {

//                                byte[] charValue = characteristic.getValue();
//                                String str_result = bytesToHex(charValue);
//                                Log.d("onCharacteristicfullres",str_result);
                                //Toast.makeText(activity, "On char changed  "+str_result, Toast.LENGTH_SHORT).show();


                            }
                        });
                    }
                    @Override
                    public void onDescriptorWrite(final BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)
                    {
                        activity.runOnUiThread(new Runnable() {
                            public void run()
                            {
                                Log.d("oncharadesc","abcd");
                               // prgd_progress.HideProgressDialog();

                                BluetoothGattService service = gatt.getService(UUID.fromString(SERVICE_ID));

                                for (BluetoothGattCharacteristic characteristics: service.getCharacteristics())
                                {
                                    Log.d("getit",characteristics.getUuid().toString());
                                }

                                final BluetoothGattCharacteristic characteristic =
                                        gatt.getService(UUID.fromString(SERVICE_ID)).getCharacteristics().get(0);


                                byte[] byt_arr;

                                byt_arr = hexStringToByteArray(value);

                                characteristic.setValue(byt_arr);
                                gatt.writeCharacteristic(characteristic);


                            }
                        });

                    }


                };
        BluetoothGatt bluetoothGatt =  bluetoothDevice.connectGatt(activity, true, gattCallback);

    }

Upvotes: 2

Views: 3198

Answers (3)

Dushyant Suthar
Dushyant Suthar

Reputation: 671

Firstly as mentioned in other answers you should not create multiple instances of BluetoothGattCallback just implement those in a way that they exists as single entity for every device for example holding those objects in HashMap or things like that. I also would like to add check if you receive buzy state from ble. It happens on some ble's that they notify twice for single write first response represents buzy state and other gives us the data, well depends on device to device. Thus, kindly perform some checks on ble's behaviour too.

Upvotes: 1

Andrey
Andrey

Reputation: 21

I agree with Emil. Try to establish a connection first, and if the connection is successful, try writing something to the characteristic or descriptor. Also note that in the method writeData() the BluetoothGattCallback is constantly created, it needs to be created only once for each connected device and the caching of the result of the onServicesDiscovered() method so as not to cause it constantly.

Upvotes: 0

Emil
Emil

Reputation: 18442

It's because you call connectGatt multiple times. Every time you call connectGatt you create a GATT client object which listens to notifications. So after three presses you will have three GATT clients that all handles each notification.

You should change the code so that you use the previously created GATT client when you write your data.

Upvotes: 4

Related Questions