Search code examples
androidbluetoothbroadcastreceiverlistadapter

Bluetooth devices discovery and custom list adapter


I'm trying to retrieve a list of visible Bluetooth devices and pass gathered information to a ListView using custom adapter. The only problematic part of my function is adding discovered items(devices) to a ListView, where while testing different approaches, either ListView is not populated at all, items get overwritten or items become duplicate within ListView.

My current function does not populate ListView at all:

public void startDevicesDiscovery(){

    rowItemsDevices.clear();
    devicesAdapter =new DevicesListAdapter(tContext, rowItemsDevices);

    //cancel discovery if discovering
    if (mBluetoothAdapter.isDiscovering()){
        mBluetoothAdapter.cancelDiscovery();
    }
    general.log("BT","start list size: "+rowItemsDevices.size());
    bluetoothReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            General general = new General(tContext);
            String action = intent.getAction();

            // if device found
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {

                btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                if(btDevice == null){
                    general.log("BT","device NULL");
                }else{

                    Device device = new Device(btDevice.getName(),btDevice.getAddress());

                    general.log("BT","device: "+device.getDeviceName()+"\ndevice MAC: "+device.getMacAddress());

                    RowItemDevices items = new RowItemDevices(device.getDeviceName(),device.getMacAddress());
                    rowItemsDevices.add(items);
                    devicesAdapter.notifyDataSetChanged();
                }

            }else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
                general.log("BT","device search finished");
                general.log("BT","end list size: "+rowItemsDevices.size());
            }

        }
    };

    visibleDevices.setAdapter(devicesAdapter);

    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_FOUND);
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(bluetoothReceiver, filter);

    mBluetoothAdapter.startDiscovery();

}

Logs show that devices were discovered correctly: enter image description here

In order to exclude causes of the problem being in my custom ListView adapter itself, I created a test function which proves that adding elements to my ListView works correctly:

public void testListView(){
    general.log("BT","testListView");
    rowItemsDevices.clear();
    devicesAdapter =new DevicesListAdapter(tContext, rowItemsDevices);
    RowItemDevices items = new RowItemDevices("test 1","test sub 1");
    rowItemsDevices.add(items);
    RowItemDevices items2 = new RowItemDevices("test 2","test sub 2");
    rowItemsDevices.add(items2
    );
    visibleDevices.setAdapter(devicesAdapter);
}

Any ideas what is wrong here? It looks like function startDevicesDiscovery works as expected but maybe I am implementing it not the right way?

EDIT:

After adding devicesAdapter.notifyDataSetChanged() on my adapter, the list is showing correct values on first run, yet if I run the function again, the items become duplicate so that is the same problem I had at the beginning. By looking at the logs, I can see that the problem is cause by the BroadcastReceiver which, for some reason, on the second search, addz previously discovered devices to the new search. How to fix it? enter image description here


Solution

    1. To make ListView show added items, you have to tell ListVIew that something is updated in it's list: add yourAdapter.notifyDataSetChanged() after rowItemsDevices.add(items);. Without it ListView will newer know that he already has some items to draw.
    2. The items now are duplicated because you register new BroadcastReceiver, and don't unregister the old one. If you try to run your method 3rd time, you will get 3-plicated items. So you have to unregister the receiver after scan finished:

      else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
          general.log("BT","device search finished");
          general.log("BT","end list size: "+rowItemsDevices.size());
          unregisterReceiver(this); //add this line
      }