在开始扫描时,BluetoothLeScanner应用程序崩溃,并且不显示任何结果

时间:2018-04-24 15:58:33

标签: android android-bluetooth android-ble

我看到的错误信息是:

  

尝试调用虚拟方法' void android.bluetooth.le.BluetoothLeScanner.startScan(java.util.List,android.bluetooth.le.ScanSettings,android.bluetooth.le.ScanCallback)' com.example.drodo.diamondbeacons.BleDevicesActivity.startScanning(BleDevicesActivity.java:91)中的空对象引用,位于com.example.drodo.diamondbeacons.BleDevicesActivity $ 1.onClick(BleDevicesActivity.java:68)。行错误:mBluetoothLeScanner.startScan(buildScanFilters(),buildScanSettings(),mScanCallback);

这是我的代码:

public class BleDevicesActivity extends AppCompatActivity {

private Toolbar bleToolbar;

private static final String TAG = BleDevicesActivity.class.getName();

private static final long SCAN_PERIOD = 5000;

private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private ScanCallback mScanCallback;
private TextView deviceName;
private TextView deviceAddress;
private Button scanDevicesBtn;
private Handler mHandler;

public void setBluetoothAdapter(BluetoothAdapter btAdapter) {
    this.mBluetoothAdapter = btAdapter;
    mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ble_devices);

    mHandler = new Handler();

    bleToolbar = (Toolbar) findViewById(R.id.ble_toolbar);
    setSupportActionBar(bleToolbar);
    getSupportActionBar().setTitle("Ble Devices Nearby");
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    deviceName = (TextView) findViewById(R.id.device_name_text);
    deviceAddress = (TextView) findViewById(R.id.device_address_text);
    scanDevicesBtn = (Button) findViewById(R.id.scan_devices_btn);

    scanDevicesBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startScanning();

            Snackbar.make(v, "Scanning for BLE Devices Nearby", Snackbar.LENGTH_SHORT)
                    .setAction("Action", null).show();
        }
    });
}

public void startScanning() {
    if (mScanCallback == null) {
        Log.d(TAG, "Starting Scanning");

        // Will stop the scanning after a set time.
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                stopScanning();
                Toast.makeText(BleDevicesActivity.this, "Scanning Stopped", Toast.LENGTH_SHORT).show();
            }
        }, SCAN_PERIOD);

        // Kick off a new scan.
        mScanCallback = new SampleScanCallback();
        mBluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), mScanCallback);

        String toastText = getString(R.string.scan_start_toast) + " "
                + TimeUnit.SECONDS.convert(SCAN_PERIOD, TimeUnit.MILLISECONDS) + " "
                + getString(R.string.seconds);
        Toast.makeText(BleDevicesActivity.this, toastText, Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(BleDevicesActivity.this, R.string.already_scanning, Toast.LENGTH_SHORT).show();
    }
}

/**
 * Stop scanning for BLE Advertisements.
 */
public void stopScanning() {
    Log.d(TAG, "Stopping Scanning");

    // Stop the scan, wipe the callback.
    mBluetoothLeScanner.stopScan(mScanCallback);
    mScanCallback = null;

    // Even if no new results, update 'last seen' times.
    //amAdapter.notifyDataSetChanged();
}

/**
 * Return a List of {@link ScanFilter} objects to filter by Service UUID.
 */
private List<ScanFilter> buildScanFilters() {
    List<ScanFilter> scanFilters = new ArrayList<>();

    ScanFilter.Builder builder = new ScanFilter.Builder();
    builder.setServiceUuid(BleConstants.Service_UUID);
    scanFilters.add(builder.build());

    return scanFilters;
}

/**
 * Return a {@link ScanSettings} object set to use low power (to preserve battery life).
 */
private ScanSettings buildScanSettings() {
    ScanSettings.Builder builder = new ScanSettings.Builder();
    builder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
    return builder.build();
}

/**
 * Custom ScanCallback object - adds to adapter on success, displays error on failure.
 */
private class SampleScanCallback extends ScanCallback {

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        super.onBatchScanResults(results);

        for (ScanResult result : results) {
            String device_name = result.getDevice().getName();
            String device_address = result.getDevice().getAddress();

            deviceName.setText(device_name);
            deviceAddress.setText(device_address);
        }

    }

    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        try {
            ScanRecord scanRecord = result.getScanRecord();

            assert scanRecord != null;
            byte[] manufacturerData = scanRecord.getManufacturerSpecificData(0x0590);

            assert manufacturerData != null;

            double lightValue = Double.parseDouble(Arrays.toString(new byte[]{manufacturerData[0]}).replace("[", "").replace("]", ""));
            double tempValue = Double.parseDouble(Arrays.toString(new byte[]{manufacturerData[1]}).replace("[", "").replace("]", ""));
            double batteryValue = Integer.parseInt(Arrays.toString(new byte[]{manufacturerData[2]}).replace("[", "").replace("]", ""));
            int alertPresses = Integer.parseInt(Arrays.toString(new byte[]{manufacturerData[3]}).replace("[", "").replace("]", ""));

            Toast.makeText(BleDevicesActivity.this, "LIGHT: " + lightValue + " %", Toast.LENGTH_SHORT).show();
            Toast.makeText(BleDevicesActivity.this, "TEMPERATURE: " + tempValue + " \u2103", Toast.LENGTH_SHORT).show();
            Toast.makeText(BleDevicesActivity.this, "BATTERY LEVEL: " + batteryValue + " Volts", Toast.LENGTH_SHORT).show();
            Toast.makeText(BleDevicesActivity.this, "ALERT PRESSES: " + alertPresses, Toast.LENGTH_SHORT).show();

        } catch (Exception e) {

            String error_message = e.getMessage();
            Toast.makeText(BleDevicesActivity.this, "Error: " + error_message, Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public void onScanFailed(int errorCode) {
        super.onScanFailed(errorCode);
        Toast.makeText(BleDevicesActivity.this, "Scan failed with error: " + errorCode, Toast.LENGTH_LONG)
                .show();
    }
}
}

可能导致崩溃的原因是什么?

1 个答案:

答案 0 :(得分:0)

这一行:

mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

正在将您的BluetoothLeScanner实例初始化为null

方法getBluetoothLeScanner仅在设备上实际开启的蓝牙时返回非null。因此,每次都需要使用扫描程序(而不是存储引用)时调用getBluetoothLeScanner ,并在使用之前积极检查结果是否为null 。如果结果为null,您可能需要在继续之前提示用户启用蓝牙。

在您的具体情况下,您应该:

  • 删除mBluetoothLeScanner字段;
  • 将行mBluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), mScanCallback); 替换为

    BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
    if (scanner != null) {
        scanner.startScan(buildScanFilters(), buildScanSettings(), mScanCallback);
    } else {
        // Device Bluetooth is disabled; check and prompt user to enable.
    }
    
  • 将行mBluetoothLeScanner.stopScan(mScanCallback); 替换为

    BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
    if (scanner != null) {
        scanner.stopScan(mScanCallback);
    } else {
        // Device Bluetooth is disabled; scanning should already be stopped, nothing to do here.
    }