I am keep on getting the NoClassDefFoundError when my class is loaded.
The code is taken from BluetoothLeGatt project -
http://developer.android.com/samples/BluetoothLeGatt/project.html
My code:
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() { //java.lang.NoClassDefFoundError...
#Override
public void onLeScan(final BluetoothDevice device,
final int rssi, final byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
String msg= device.getAddress();
Log.d(TAG,msg);
addItems(msg);
}
});
}
};
Someone suggested that the error is because my device doesn't support BLE but I want to get rid of this error for any device. So if it doesn't support BLE feature then simply skip this error else continue with the call to this BluetoothAdapter.LeScanCallback.
NOTE:
See this my previous SO post for more clarification.
Putting the BLE feature check as the first line onCreate() doesn't stop the crash --
#Override
public void onCreate(Bundle savedInstanceState) {
if (!bleCheck()) {
Toast.makeText(getApplicationContext(), R.string.ble_not_supported,
Toast.LENGTH_SHORT).show();
finish();
}
//Rest of the code
//Call to BLE Scan on button click that causes error..
}
private boolean bleCheck() {
boolean result = false;
if (getPackageManager().
hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
result = true;
}
return result;
}
As BluetoothAdapter.LeScanCallback was Added in API level 18 ; Source, this code would need a API level check also. Here's how i have gone about this, not declared the callback as private but under the condition:
boolean apiJBorAbove = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2 ? true
: false;
boolean isBleAvailable = getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH_LE) ? true : false;
// Use this check to determine whether BLE is supported on the device.
if (isBleAvailable && apiJBorAbove) {
// Initializes a Bluetooth adapter.
// For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Ensures Bluetooth is available on the device and it is enabled.
// If not, displays a dialog requesting user permission to enable
// Bluetooth.
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
startActivity(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));
}
BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device,
final int rssi, final byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
String msg= device.getAddress();
// Log.d(TAG,msg);
// addItems(msg);
}
});
}
};
}
The NoClassDefFoundError is due to the API , not on the basis of PackageManager.FEATURE_BLUETOOTH_LE.
Related
I have faced with the issue using startScan method of BluetoothLeScanner a BLE device was found, but when I turned off BLE device my phone still shows this device as turned on !!
I have tried to use:
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i("ScanCallback", String.format("onScanResult(int callbackType[%d], ScanResult result)", callbackType));
final BluetoothDevice btDevice = result.getDevice();
if (btDevice == null){
Log.e("ScanCallback", "Could not get bluetooth device");
return;
}
final String macAddress = btDevice.getAddress();
if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) {
// NOTE: I've never got here
final BluetoothDevice outOfRangeDevice = mBtDevices.get(macAddress);
...
} else {
...
}
}
...
};
Guy, I have not found solution how to detect that BLE device is lost in other resources like (Android SDK reference, forums, stackoverflow and etc) (:
Any help will be appreciated !!
During googling and exploring the Android Documentations I have figured out how to detect if device is out of range. I would like to share my solution how I did it:
...
public void scanBLEDevices(final boolean enable) {
if(mLeScanner == null) {
Log.d(TAG, "Could not get LEScanner object");
throw new InternalError("Could not get LEScanner object");
}
if (enable) {
startLeScan();
} else {
stopLeScan(false);
}
}
private void startLeScan() {
Log.i(TAG, "startLeScan(BluetoothLeScanner mLeScanner)");
mScanning = true;
mInRangeBtDevices.clear();
if (mStartScanCallback != null) {
mHandler.removeCallbacks(mStartScanCallback);
}
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLeScanner.startScan(mScanFilters, mScanSettings, mScanCallback);
}
mStopScanCallback = new Runnable() {
#Override
public void run() {
stopLeScan(true);
}
};
mHandler.postDelayed(mStopScanCallback, SCAN_PERIOD);
}
private void stopLeScan(final boolean isContinueAfterPause) {
Log.i(TAG, "stopLeScan(BluetoothLeScanner mLeScanner)");
mScanning = false;
if (mStopScanCallback != null) {
mHandler.removeCallbacks(mStopScanCallback);
}
removeOutOfRangeDevices();
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLeScanner.stopScan(mScanCallback);
}
if (isContinueAfterPause) {
mStartScanCallback = new Runnable() {
#Override
public void run() {
startLeScan();
}
};
mHandler.postDelayed(mStartScanCallback, SCAN_PAUSE);
}
}
private void removeOutOfRangeDevices() {
final Set<String> outOfRangeDevices = new HashSet<>();
for (String btAddress : mBtDevices.keySet()) {
if (!mInRangeBtDevices.contains(btAddress)) {
outOfRangeDevices.add(btAddress);
}
}
for (String btAddress : outOfRangeDevices) {
final BluetoothDevice outOfRangeDevice = mBtDevices.get(btAddress);
mBtDevicesRSSI.remove(btAddress);
mBtDevices.remove(btAddress);
}
}
...
Explanation:
As you can see I have added on each scanning period mInRangeBtDevices collection that will keep all devices found during the current scanning.
When I stop scanning, I am also removing out of range device from previous lists that is not available anymore using one additional helper collection outOfRangeDevices
I think this example would be usefull and you will be able to integrate it in your own code
This one is looking good (JAVA):
As I understood, you need to implement startLeScan().
Find BLE devices
To find BLE devices, you use the startLeScan() method. This method takes a BluetoothAdapter.LeScanCallback as a parameter. You must implement this callback, because that is how scan results are returned. Because scanning is battery-intensive, you should observe the following guidelines:
As soon as you find the desired device, stop scanning.
Never scan on a loop, and set a time limit on your scan. A device that was previously available may have moved out of range, and continuing to scan drains the battery.
The following snippet shows how to start and stop a scan:
public class DeviceScanActivity extends ListActivity {
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
...
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
...
}
...}
Consider checking this tutorial as well.
Also this one.
I have a dialog that scans for BLE devices for 10 seconds. When I start my scan I enable a spinner at the footer of the list. When the scan is completed I'd like to remove that spinner. I'm trying to get this to work with the deprecated mBluetoothAdapter.stopLeScan(callback) function instead of the new startScan/stopScan functions as if the device isn't running version 21 or higher, you have to fallback to this method.
stopLeScan requires the same callback as startLeScan but I dont think I see the callback being made. I was hoping that it was a simple check to see if the BluetoohDevice was null, then the callback was made because the scan was stopped, but this didn't work.
With the old version of the SDK, how do you get when the scan has been stopped (either due to the proper device being found or the scan time completed)? I could pass another handler to the my scanLeDevice function, but that just seems silly as I'm already passing a callback.
Bluetooth scanner
public class BleDevice {
private final static String TAG = BleDevice.class.getSimpleName();
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
public BleDevice() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = new Handler();
}
public void scanLeDevice(final boolean enable, final BluetoothAdapter.LeScanCallback callback) {
if (enable == true && mScanning == false) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// Turn off scanning
scanLeDevice(false, callback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(callback);
Log.d(TAG, "Starting Bluetooth LE scan");
} else if(enable == false && mScanning == true) {
mScanning = false;
mBluetoothAdapter.stopLeScan(callback);
Log.d(TAG, "Stopped Bluetooth LE scan");
}
}
}
Callback in Dialog Box:
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.d(TAG, device.getAddress() + " " + device.getName() + "");
if(device == null) {
Log.d(TAG, "Device is null? stop?");
} else {
btAdapter.add(device);
}
}
};
In mBluetoothAdapter.stopLeScan(callback); the callback is just used to identify which scan is to be stopped and it's not supposed to trigger any method in the callback. It's a synchronous operation.
And the BluetoothAdapter.LeScanCallback class doesn't even have any methods beyond the onLeScan() which just receives the results.
So, you can define your own method to be triggered when the scan is stopped by you:
...
} else if(enable == false && mScanning == true) {
mScanning = false;
mBluetoothAdapter.stopLeScan(callback);
Log.d(TAG, "Stopped Bluetooth LE scan");
onScanStopped(); // <--- Remove the spinner here.
}
I'm not aware of any automatic timeout for startLeScan(), so as far as I know it should only stop by calling stopLeScan(). And onLeScan() being triggered doesn't stop the scan either.
I've seen plenty of questions about how to connect to multiple devices purposely. But in my situation, I am only trying to connect to one hardware device.
I have two hardware devices that are supposed to do the same thing. When they connect to my app via BLE, then they have an LED that turns a solid color. This all works fine and dandy when I only have one device turned on. However, when I turn two of the devices on and then try to connect to just one. Both of the devices' LED's turn solid. Although I don't seem to be getting any incoming data from the one that I didn't intend to connect to.
I don't think it's the device's fault. Because I don't have this issue on iOS. I think the phone might be remembering previously connected devices somewhere maybe?
I'm sorry, this is a lot of code. But I feel like it's important to have this whole class. Any help is much appreciated.
package com.roberts.croberts.orange;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.bluetooth.le.BluetoothLeScanner;
import java.util.ArrayList;
import java.util.List;
#TargetApi(21)
public class BluetoothRegulator {
private static BluetoothRegulator instance = null;
private Context context;
private BluetoothLeScanner mLEScanner;
private BluetoothDevice orangeDevice;
//scanner stuff
private Handler mHandler;
// Stops scanning after 3 seconds.
private static final long SCAN_PERIOD = 3000;
//connected stuff
private android.bluetooth.BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
public ArrayList<BluetoothDevice> devices = new ArrayList<>();
private Handler foundHandler = new Handler();
private Handler servicesHandler = new Handler();
private ScanCallback mScanCallback;
public static BluetoothRegulator sharedInstance(){
if(instance == null) {
instance = new BluetoothRegulator();
Log.i("chase", "created new instance");
}
return instance;
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
Log.i(TAG, "BR: onconnectionsStateChanged Connected to GATT server.");
// Attempts to discover services after successful connection.
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Loops through available GATT Serviceokay so ees.
for (BluetoothGattService gattService : mBluetoothGatt.getServices()) {
for (BluetoothGattCharacteristic gattCharacteristic : gattService.getCharacteristics()) {
mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
Log.i(TAG, mBluetoothGatt == null ? "mbluetooth is null" : "should be subscribed");
}
}
Log.i("chase", "did connect and discover devices");
} else {
Log.w(TAG, "Not Success onServicesDiscovered received: " + status);
connect(orangeDevice);
}
}
private Object getFieldFromObject(Object obj, String name){
try {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
}catch(Exception e){
Log.i("chase", "e: "+e);
return null;
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
Log.i("BR: chase", "received data!");
}
};
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
public boolean initialize(android.bluetooth.BluetoothManager btmanager, Context ctx) {
mBluetoothManager = btmanager;
context = ctx;
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
setUpCallBack();
}
return true;
}
public void scan() { //we call scan when they hit the connect button...
// Stops scanning after a pre-defined scan period.
Log.i("chase", "start scanning");
devices = new ArrayList<>();
if (mHandler == null) mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(mScanCallback);
}
}
private void foundDevice(BluetoothDevice device){
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 5 && (deviceName.substring(0, 6).equals("orange") || deviceName.substring(0, 6).equals("smartb"))) {
for (BluetoothDevice d : devices){
if (d.getAddress().equals(device.getAddress())){
return;
}
}
mHandler.removeCallbacksAndMessages(null);
devices.add(device);
if (devices.size() == 1) { //wait one second and then assume there aren't any more devices named "orange"
foundHandler.postDelayed(new Runnable() {
public void run() {
doneSearching();
}
}, 1000);
}
}
}
private void doneSearching(){
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
if (devices.size() == 1){
BluetoothDevice device = devices.get(0);
connect(device);
}else{
//normally this displays a list and the user can choose which device. But this works just as well for now.
BluetoothDevice device = devices.get(0);
connect(device);
}
}
//connect method
public boolean connect(BluetoothDevice btdevice) {
orangeDevice = btdevice;
if (mBluetoothAdapter == null || btdevice == null || btdevice.getAddress() == null) {
return false;
}
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
devices = new ArrayList<>();
mBluetoothGatt = orangeDevice.connectGatt(context, true, mGattCallback);
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) return;
mBluetoothGatt.disconnect();
mBluetoothGatt = null;
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
foundDevice(device);
}
};
public void setUpCallBack(){
mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
foundDevice(device);
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Chase", "Scan Failed Error Code: " + errorCode);
}
};
}
}
Update
I was playing around with a galaxy tablet and wasn't able to recreate the issue. So I think it's device dependent. The problem occurs on the Galaxy S3, and I am trying to round up some other devices to test with.
Also, I was able to get my hands on some new devices and it seems that if the device has never been connected before to the phone (virgin device) then that device doesn't get mixed up and think it's connected when it's not. So we will see it when we search but it never thinks I am connecting to it, until I actually do connect to it. After that, then half the time it thinks I am trying to talk to it when I am not. I hope that makes sense. Which backs up the theory that the phone is somehow caching old devices. I tried uninstalling the app and reinstalling it to see if it would have the same effect as using a virgin device, but it seems the app has nothing to do with it. The device will still connect (when it's not supposed to) after it has been introduced to the phone, even if I did a fresh install of the app.
I would check the BLE devices themselves. Is there a chance that they might have the same System ID ? I believe it's the first characteristic in 0x180A. If so - it will be difficult for the host to distinguish them and such a double connection might happen.
-Lets say you have 2 devices. So foundDevice() gets called. Now devices arraylist contains 1 device.
-After that you are using handler which calls doneSearching() & checks
if device.size()==1
It returns true and you call connect()
-Inside connect you are again creating an arraylist i.e
devices = new ArrayList<>();
So what happens now is your devices ArrayList<>() contains 0 elements.
-So now when 2nd device is found again the above steps are repeated because whenever connect method is getting called, the size of list is getting refreshed to 0
So just remove the line
devices = new ArrayList<>();
inside connect() method
I've just updated my Nexus 5 and my app's feature has stopped working.
The reason is that the interface LeScanCallback is not calling the function onLeScan. On the below code, I'm using some deprecated code, but I need to do it since I'm testing some technology. This is how I start my bluetooth adapter:
#Override
protected void onStart()
{
super.onStart();
// Check if the device has BLE
if (!this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
{
bleNotSupported();
return;
}
// Initializes a Bluetooth adapter.
final BluetoothManager bluetoothManager = (BluetoothManager)this.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
{
bleNotEnabled();
/*
* Bluetooth can be enabled in app:
*
* Intent btIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
* btIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
* mAppContext.startActivity(btIntent);
*/
return;
}
boolean bluetoothScanning = mBluetoothAdapter.startLeScan(mScanCallback); // this is true as well
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onStop() {
super.onStop();
if (mBluetoothAdapter != null)
{
mBluetoothAdapter.stopLeScan(mScanCallback);
}
progressBar.setVisibility(View.GONE);
mDeviceAdapter.clearList();
}
BluetoothAdapter.LeScanCallback mScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)
{
// if (previousBluetoothSelected == null)
mDeviceAdapter.refreshList(device);
if (device.getAddress().equalsIgnoreCase(previousBluetoothSelected)) {
selectDeviceAndGo(device);
mBluetoothAdapter.stopLeScan(this);
}
}
};
and it works in each device with API < 23, but not in API = 23.
What could be the reason?
Thank you very much in advance.
Regards.
Rafael.
There is A bug on some of the Nexus 5 phones with Marshmallow. in some phones the scan wont start if your gps is off.
I want to analysis the heart rate of a heart rate monitor. For that I want to save the last used device and compare it to the found devices. Because it takes a while to find devices, mDevice remains null. What do I have to do to update mDevice properly?
private ArrayList<BluetoothDevice> mDeviceList;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private BluetoothDevice mDevice;
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
protected void onStart() {
super.onStart();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
// Initializes list view adapter.
mDeviceList = new ArrayList<BluetoothDevice>();
scanLeDevice(true);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
final String adress = prefs.getString(getString(R.string.device_address), "");
for(BluetoothDevice b : mDeviceList){
if(b.getAddress().equals(adress)){
mDevice = b;
}
}
if(mDevice != null)
Log.e(TAG, mDevice.getAddress());
}
taken from the google manual:
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(!mDeviceList.contains(device)){
mDeviceList.add(device);
}
}
});
}
};
I hope these are enough information. If something is missing, feel free to ask
The scan is a background activity your trying to look at the results straight after you start it rather than waiting for it to finish. You may want to put your checking code into the onLeScan call-back directly and stopping the scan as soon as you see the device you want.
You could also try not doing the scan all together if you already have the details for the device just try going straight to connect. The details of if you need to scan before you connect are not at all clear from the documentation so you need to be prepared to experiment a bit as it's still all far too flaky.
Just move your code where you try to find the last device (everything in onStart() after SharedPreferences prefs...) to after you have already found devices, for example at the end of your runnable (after invalidateOptionsMenu();)