BluetoothAdapter won't stop scanning for BLE devices

12,006

Solution 1

Every time you call getLeScanCallback you create new instance of ScanCallback and lost reference to previous instance.

stopScan stops ongoing scan regardless what instance you pass BUT if it is a different instance (than the one you used to start) it will not remove old instance of callback so still some events will be delivered to it before it stops.

Solution 2

Scan results will not stop immediately, but will eventually stop. There is a queue of pending results that you can flush with:

scanner.flushPendingScanResults();

But even then, the documentation is clear that it will send whatever it has found to the callback. This happens even if you have stopped scanning. Poor API design, but it is what it is.

The easiest I think is to set a flag to ignore the scan results after you have stopped them.

Solution 3

I haven't noticed any issues with your code, it seems to be fine. Perhaps there's an issue with your getLeScanCallback() method?

Instead of having a method to return your ScanCallback, you could declare it as a member variable so you would have leScanCallback = new ScanCallback() and then you could just refer to this member variable instead when trying to stop the scan.

bluetoothAdapter.getBluetoothLeScanner().stopScan(leScanCallback);

Depending on what version of Android you're supporting, it might be worthwhile adding the startLeScan and stopLeScan methods which Rajesh Panchal suggested for pre Lollipop Android devices.

Share:
12,006
Michał Witanowski
Author by

Michał Witanowski

Updated on July 14, 2022

Comments

  • Michał Witanowski
    Michał Witanowski almost 2 years

    In my app i have start and stop button, when user press start i call startScan method

    bluetoothAdapter.getBluetoothLeScanner().startScan(getLeScanCallback());
    

    When user press stop i call stopScan however it doesn't seem to do anything. BluetoothAdapter keeps scanning for new devices.

    bluetoothAdapter.getBluetoothLeScanner().stopScan(getLeScanCallback());
    

    Here is my getLeScanCallback method:

    private ScanCallback getLeScanCallback(){
        ScanCallback leScanCallback = new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                super.onScanResult(callbackType, result);
                boolean duplicate = false;
                for(Device d : devices) {
                    if(d.getAddress().equals(result.getDevice().getAddress()))
                        duplicate = true;
                }
                if(!duplicate) {
                    Device device = new Device();
                    device.setName(result.getDevice().getName());
                    device.setAddress(result.getDevice().getAddress());
                    device.setStatus(getString(R.string.disconnected));
                    devices.add(device);
                    deviceListAdapter.notifyDataSetChanged();
                }
            }
    
            @Override
            public void onBatchScanResults(List<ScanResult> results) {
                super.onBatchScanResults(results);
            }
    
            @Override
            public void onScanFailed(int errorCode) {
                super.onScanFailed(errorCode);
            }
        };
    
        return leScanCallback;
    }
    

    It gets called even after stopScan() was called. What am I doing wrong or in other words, how to stop scanning for BLE devices?

  • Michał Witanowski
    Michał Witanowski over 7 years
    I don't think there are such methods as startLeScan and stopLeScan.
  • Rajesh Panchal
    Rajesh Panchal over 7 years
    I did have used in my project
  • Michał Witanowski
    Michał Witanowski over 7 years
    There are bluetoothAdapter.startLeScan() and bluetoothAdapter.stopLeScan() but they are deprecated.
  • Igor Fridman
    Igor Fridman almost 7 years
    Those methods are depricated
  • HughHughTeotl
    HughHughTeotl almost 6 years
    That is very good to know. When you say "The documentation is clear that..." can you point us toward the relevant docs? Thanks
  • BjornW
    BjornW over 5 years
    This seems to be a completely incorrect answer. You don't "start" a scan with the ScanCallback instance. All the start and stop calls get its own instance, and that particular instance is called upon completion or failure. The code is fine, you just have to be prepared on that the system might deliver results after the stopScan.
  • RadekJ
    RadekJ over 5 years
    If stopScan is called with new callback there is still some events delivered to previous callback before scan is stopped. If you will use the same callback instance, it will remove it instantly and no events will be delivered to it (even though stopping scan might not be instant).
  • alexc
    alexc about 5 years
    @BjornW That's not correct. Look at the source code of BluetoothLeScanner, if the callback you pass to stopScan is not the same as the one passed to startScan, then stopScan has no effect
  • BjornW
    BjornW about 5 years
    @alexc actually I don't even understand my previous comment, reading it now :) I remember having to fix this myself as well, and I looked at the underlying source and android debug output and figured it out, but it must be badly documented..