android 藍芽BLE多連線
阿新 • • 發佈:2019-02-14
最近做藍芽BLE的開發,此專案和網上別人的稍微有點不同,手機需要連線多個BLE裝置,此部分網上的資料很少,所以拿出來和大家分享一下
//初始化
private void initBt() { manager = BluetoothManager.getInstance(); manager.setContext(this); if (!getPackageManager().hasSystemFeature( PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "您的手機不支援BLE", Toast.LENGTH_SHORT).show(); finish(); } BluetoothAdapter btaAdapter = BluetoothAdapter.getDefaultAdapter(); if (!btaAdapter.isEnabled()) { btaAdapter.enable(); } if (!manager.isScanning) new ScanLeTask().execute(); }
//掃描ble 裝置
private class ScanLeTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { manager.scanLeDevice(true, mLeScanCallback); return null; } } // 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() { Log.d(TAG, device.getName()); BtDevice mDevice = new BtDevice(device.getAddress(), device.getName()); if (!mList.contains(mDevice)) { mList.add(mDevice); View view = getLayoutInflater().inflate( R.layout.deviceitem, null); view.setTag(mList.size() - 1); TextView textView = (TextView) view .findViewById(R.id.name); Button button = (Button) view.findViewById(R.id.icon); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { View view = (View) v.getParent(); int index = (Integer) view.getTag(); manager.connect(mList.get(index).getAddr(), index); Log.d(TAG, "index is:" + index); } }); textView.setText(mDevice.getName()); container.addView(view); } } }); } };
//封裝的核心類
public class BluetoothManager { protected static final String TAG = "BluetoothManager"; private Context context; public boolean isScanning; private int index; private Handler handler = new Handler(); // 10秒後停止查詢搜尋. private static final long SCAN_PERIOD = 10000; private static BluetoothAdapter btaAdapter = BluetoothAdapter .getDefaultAdapter(); // public static BluetoothGatt mBluetoothGatt; private int disconStatus; public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; public final static UUID UUID_HEART_RATE_MEASUREMENT = UUID .fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); private static BluetoothManager instance; private BluetoothManager() { } public static BluetoothManager getInstance() { if (instance == null) { synchronized (BluetoothManager.class) { if (instance == null) { instance = new BluetoothManager(); } } } return instance; } public void setContext(Context mContext) { context = mContext; } private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { Log.d(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.d(TAG, "Attempting to start service discovery:" + gatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.d(TAG, "Disconnected from GATT server."); if (disconStatus == 129) { close(gatt); Log.d(TAG, "----129----"); btaAdapter.disable(); try { Thread.sleep(2500); } catch (InterruptedException e) { e.printStackTrace(); } btaAdapter.enable(); } } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { if (gatt == null) return; // writeData(gatt, new byte[] { 0x11, 0x12 }); // displayGattServices(gatt.getServices()); Log.d(TAG, "BluetoothGatt.GATT_SUCCESS"); } else { Log.d(TAG, "onServicesDiscovered received: " + status); disconStatus = status; } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { // broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); Log.d(TAG, "onCharacteristicRead"); // Toast.makeText(BluetoothLeService.this, // "onCharacteristicRead successfully", 100).show(); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { // broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); Log.d(TAG, "onCharacteristicChanged"); } }; public void writeData(BluetoothGatt gatt, byte[] datas) { if (/* btaAdapter == null || */gatt == null) { Log.w(TAG, "BluetoothGatt is null can not writeData."); return; } BluetoothGattService gattService = gatt.getService(UUID .fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT)); if (gattService == null) { Log.w(TAG, "the gattService for BluetoothGattService is null,can not write data"); return; } BluetoothGattCharacteristic characteristic = gattService .getCharacteristic(UUID .fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); if (characteristic == null) { Log.w(TAG, "the uuid for BluetoothGattCharacteristic is null,can not write data"); return; } characteristic.setValue(datas); // gatt.writeCharacteristic(characteristic); Log.i(TAG, "writeCharacteristic" + gatt.writeCharacteristic(characteristic)); } /** * Enables or disables notification on a give characteristic. * * @param characteristic * Characteristic to act on. * @param enabled * If true, enable notification. False otherwise. */ public void setCharacteristicNotification( BluetoothGattCharacteristic characteristic, boolean enabled) { BluetoothGatt gatt = MainActivity.mList.get(index).getmBluetoothGatt(); if (btaAdapter == null || gatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } gatt.setCharacteristicNotification(characteristic, enabled); // This is specific to Heart Rate Measurement. if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { BluetoothGattDescriptor descriptor = characteristic .getDescriptor(UUID .fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); } } private boolean isPrepared; public void scanLeDevice(final boolean enable, final BluetoothAdapter.LeScanCallback mLeScanCallback) { if (!isPrepared) { isPrepared = true; Looper.prepare(); } if (enable) { // Stops scanning after a pre-defined scan period. handler.postDelayed(new Runnable() { @Override public void run() { isScanning = false; btaAdapter.stopLeScan(mLeScanCallback); Log.d(TAG, "STOP...."); } }, SCAN_PERIOD); isScanning = true; btaAdapter.startLeScan(mLeScanCallback); } else { isScanning = false; btaAdapter.stopLeScan(mLeScanCallback); } } /** * After using a given BLE device, the app must call this method to ensure * resources are released properly. */ public void close(BluetoothGatt gatt) { if (gatt == null) { return; } gatt.close(); gatt = null; } /** * Connects to the GATT server hosted on the Bluetooth LE device. * * @param address * The device address of the destination device. * * @return Return true if the connection is initiated successfully. The * connection result is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public boolean connect(final String address, int index) { this.index = index; if (address == null) { Log.w(TAG, " unspecified address."); return false; } final BluetoothDevice device = btaAdapter.getRemoteDevice(address); if (device == null) { Log.w(TAG, "Device not found. Unable to connect."); return false; } // We want to directly connect to the device, so we are setting the // autoConnect // parameter to false. // MainActivity.mList.get(index).setmBluetoothGatt(gatt); if (!MainActivity.gattMap.containsKey(MainActivity.mList.get(index) .getAddr())) { BluetoothGatt gatt = device.connectGatt(context, true, mGattCallback); MainActivity.gattMap.put(MainActivity.mList.get(index).getAddr(), gatt); Log.d(TAG, "Trying to create a new connection." + MainActivity.gattMap.size()); } else Log.d(TAG, "allready connected." + MainActivity.gattMap.size()); return true; } /** * Disconnects an existing connection or cancel a pending connection. The * disconnection result is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public void disconnect(int index) { if (btaAdapter == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } MainActivity.mList.get(index).getmBluetoothGatt().disconnect(); } }
//用於傳送資料的執行緒池
public class BluetoothExecutor {
private static final String TAG = "TcpExecutor";
private static BluetoothExecutor instance = null;
private ThreadPoolExecutor executor;
private Semaphore semp;
private BluetoothManager manager;
private BluetoothExecutor() {
executor = new ThreadPoolExecutor(1, 7, 500, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(20));
semp = new Semaphore(1);
manager = BluetoothManager.getInstance();
}
public static BluetoothExecutor getInstans() {
if (instance == null) {
synchronized (BluetoothExecutor.class) {
if (instance == null)
instance = new BluetoothExecutor();
}
}
return instance;
}
public void execute(final byte[] chars) {
Log.d(TAG, "execute start" + executor.getActiveCount());
try {
semp.acquire();
final Set<String> set = MainActivity.gattMap.keySet();
Log.d(TAG, "Set<String>" + set);
for (int i = 0; i < MainActivity.gattMap.size(); i++) {
executor.execute(new Runnable() {
@Override
public void run() {
manager.writeData(
MainActivity.gattMap.get(set.iterator().next()),
chars);
}
});
}
while (executor.getActiveCount() != 0)
;
semp.release();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}