Android手机支持BLE(蓝牙4.0)通信。笔者遇到了不少问题,供大家分享下。
1、开启蓝牙
BlueAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (!adapter.isEnabled()) {
ToastUtil.showToast("请打开蓝牙服务");
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
this.startActivity(intent);
}
else
showDevice();
2、显示附近的蓝牙
这里使用了recyclerView列出所有蓝牙。较为简单,不过要去重
ArrayList<BluetoothDevice> foundDevice = new ArrayList<>();
ArrayList<String> tempDevice = new ArrayList<>();
// 将已配对的设备加入到队列中
foundDevice.addAll(adapter.getBondedDevices());
for (BluetoothDevice device : adapter.getBondedDevices()) {
if (!tempDevice.contains(device.getName() + device.getAddress()))
tempDevice.add(device.getName() + device.getAddress());
}
LogUtil.d("showDevice", "已连接的设备" + tempDevice);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 使用弹出窗。将view加载到弹出窗中
View tempView = LayoutInflater.from(this.getContext()).inflate(R.layout.alert_show_device, null);
recyclerView = (RecyclerView) tempView.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));
// 设置recyclerView的适配器。这里较为简单就不贴出代码了。
recyclerView.setAdapter(Adapter);
builder.setView(tempView);
alertDialog = builder.create();
alertDialog.setCancelable(true);
// 监听窗口消失事件。如果窗口消失,则取消蓝牙扫描
builder.setOnCancelListener(new MyCancelListener());
builder.setOnDismissListener(new MyDimissListener());
// 显示弹出窗
alertDialog.show();
// 注册两个广播:发现蓝牙和扫描蓝牙结束
receiver = new BlueToothReceiver();
this.registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
this.registerReceiver(receiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
// 开始扫描
adapter.startDiscovery();
3、监听扫描信息,将扫描到的蓝牙加入到recyclerView中
/**
* 蓝牙广播接收器
*/
class BlueToothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 如果发现了蓝牙
if (action.equals(BluetoothDevice.ACTION_FOUND)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
LogUtil.d("onReceive", "扫描到了" + device.getName() + "\t" + device.getAddress());
// 避免重复添加
if (!tempDevice.contains(device.getName() + device.getAddress())) {
LogUtil.d("onReceive", "发现了蓝牙设备: " + device.getName() + "\t" + device.getAddress());
foundDevice.add(device);
tempDevice.add(device.getName() + device.getAddress());
recyclerView.getAdapter().notifyDataSetChanged();
LogUtil.d("onReceive", tempDevice);
}
}
// 扫描蓝牙结束了
else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
ToastUtil.showToast("扫描结束");
LogUtil.d("onReceive", "扫描结束");
}
}
}
4、监听弹出窗关闭,如果弹出窗关闭,则取消扫描
class MyCancelListener implements AlertDialog.OnCancelListener {
@Override
public void onCancel(DialogInterface dialog) {
// 停止蓝牙扫描
foundDevice.clear();
tempDevice.clear();
adapter.cancelDiscovery();
}
}
class MyDimissListener implements AlertDialog.OnDismissListener {
@Override
public void onDismiss(DialogInterface dialog) {
// 停止蓝牙扫描
foundDevice.clear();
tempDevice.clear();
adapter.cancelDiscovery();
}
}
5、实现recyclerView子项点击事件,这里由于使用了ItemClick接口,并且已经和recyclerView的adapter做了绑定。所以就不摆出代码了
// 蓝牙列表的点击事件实现
class MyBlueItemClick implements ItemClick {
@Override
public void itemClick(View view, int position) {
// 关闭弹出窗
alertDialog.dismiss();
// 连接设备,得到gatt对象
BluetoothDevice device = foundDevice.get(position);
BluetoothGatt gatt = foundDevice.get(position).connectGatt(MyApplication.context, false, new MyBack());
}
}
6、实现回调。编写MyBack类
// 蓝牙设备的监听函数
class MyBack extends BluetoothGattCallback {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
// 如果连接设备成功,则获取所有的services
if (newState == BluetoothGatt.STATE_CONNECTED) {
gatt.discoverServices());
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
// 如果查找服务成功,则获取所有的服务
if (status == BluetoothGatt.GATT_SUCCESS) {
// 得到所有的服务
List<BluetoothGattService> services = gatt.getServices();
List<BluetoothGattCharacteristic> characteristicss = new ArrayList<>();
// 遍历所有的服务,取characteristics
for (int i = 0; i < services.size(); i++) {
// 获取第i个服务
BluetoothGattService service = services.get(i);
LogUtil.d("onServicesDiscovered", service.getUuid());
characteristicss.add(service.getCharacteristics());
}
LogUtil.d("onServicesDiscovered", "================可用服务在上面");
// 输出所有的uuid
for (int i = 0; i < characteristicss.size(); i++) {
List<BluetoothGattCharacteristic> temp = characteristicss.get(i);
for (BluetoothGattCharacteristic item : temp)
LogUtil.d("onServicesDiscovered", item.getUuid());
LogUtil.d("onServicesDiscovered", "=============");
}
}
// 如果需要设置监听某一个BluetoothGattCharacteristic
gatt.setCharacteristicNotification(characteristic, true));
// 设置描述
List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
for (BluetoothGattDescriptor dp : descriptors) {
dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(dp);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
}
/**
* 从蓝牙读取数据
*
* @param gatt 读取的数据源
* @param characteristic 读取的内容
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic) {
// 解析数据
byte[] bytes = characteristic.getValue();
String s = "";
for (int i = 0; i < bytes.length; i++) {
s += (Integer.toHexString((bytes[i] & 0xff)) + " ");
}
// 控制台输出数据
Log.d("onCharacteristicChanged", characteristic.getUuid() + "\t" + s);
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
super.onDescriptorWrite(gatt, descriptor, status);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
}
7、向蓝牙发送数据
public void sendData2Device() {
BluetoothGattService service = gatt.getService(uuid1);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid2);
characteristic.setValue(new byte[]{0x01});
LogUtil.d("sendData2Device", "write:" + gatt.writeCharacteristic(characteristic));
}
}
至此,BLE收发数据就完成了