** 安卓开发中或多或少会接触到蓝牙部分,像一些智能家居,蓝牙手环,还有一些串口数据传输的设备都和蓝牙相关,面试的时候有的公司也会问到一些蓝牙相关的问题,这里我来说说关于低功耗蓝牙的一些相关知识,这些知识也是我在网上查阅总结的。在百度上一搜低功耗蓝牙的帖子很多,但都讲的不是很全面,让人知其然不知其所以然。这里我就从简单的开始先分析一些谷歌的demo的代码,看看BLE蓝牙是怎么建立通信的,只要掌握了BLE蓝牙通信那么再将发送接收的数据处理一下就ok了,当然光看这一篇帖子不一定会完全把低功耗蓝牙弄懂,兴许会遇到一些坑,但是坚持下去始终会弄懂的;**
这是网上提供的Android 蓝牙4.0 ble 官方 demo
- App的界面图
App的界面很简单就两个界面
代码主要包含四个类
DeviceScanActivity类(展示手机扫描到的BLE蓝牙);
DeviceControlActivity类(BLE操作控制台);
BluetoothLeService类(通过服务来管理蓝牙,其中通过广播来于DeviceControlActivity类通信)
SampleGattAttributes类(不同种类的UUID)
DeviceScanActivity类的功能:
这个类之间继承ListActivity,顾名思义,它可能是一个展示列表,细看代码,它切实是一个列表展示类,这个类的主要作用就是展示手机扫描到的可用蓝牙;点击选择的BLE后将BLE的属性(名称和ID)传递到DeviceControlActivity类;
该类的主要流程就是 在onCreate方法中判断手机是否支持BLE,然后初始化蓝牙适配器,最后就是手机的权限适配(蓝牙需要定位的权限)
在onResume方法中检测蓝牙是否开启,没有开启那就开启蓝牙,不开启的话那么就触发onActivityResult方法则finish()关闭app,开启蓝牙的话则
开启扫描 scanLeDevice(true); true为开启扫描 false为关闭扫描;在扫描的方法scanLeDevice中可以看到通过handler计时扫描十秒钟;
开启扫描后将会回调 mLeScanCallback 对象;在这个对象中重写了onLeScan方法,这个方法中的参数onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)中device则为蓝牙设备属性;将蓝牙设备属性展示到列表中,通listview监听选中 的蓝牙跳转到DeviceControlActivity类;
DeviceControlActivity类中要功能:
开启服务BluetoothLeService,接收服务传过来的蓝牙数据;里面有几个重要的类部类:
ServiceConnection(BinderService的返回数据接收类);BluetoothGattCallback(广播,接收服务发送过来的消息); ExpandableListView.OnChildClickListener(这是一个list二级列表的监听类);里面还有一个重要的方法就displayGattServices(listview的适配器);
该类的主要流程:注册广播并接收,在onCreate中对一些控件的初始化,通过intent传值获取到蓝牙的名称和ID,然后启动服务;在ServiceConnection内部类中得到服务的对象 mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();在 onResume方法中通过服务的对象建立蓝牙的连接,注意 蓝牙连接后还并不能通信,建立通信使用通过UUID的;蓝牙建立连接后会触发广播action为BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED方法,在这个方法中通过调用displayGattServices方法展示蓝牙的UUID的数据,可以看到蓝牙有很多UUID,其实UUID是分可读的,可写的,和可读可写的,这应该是蓝牙厂家写好的固件;在app上我们可以挨个的点击不同的UUID将会建立不同的连接,其中就有一种连接可以信;点击UUID将会OnChildClickListener()方法,里面的逻辑主要就是开启蓝牙的读取功能和开启蓝牙的的通知功能
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mBluetoothLeService.readCharacteristic(characteristic);
BluetoothLeService类主要功能:
就是通过UUID建立蓝牙通讯,readCharacteristic()开启蓝牙读的功能,setCharacteristicNotification()开启蓝牙或禁用通知的功能;getSupportedGattServices()只有在成功完成之后才会调用此函数。在连接的设备上检索受支持的有关协定服务列表,里面没有蓝牙写数据的方法,要自己写;
该类的主要流程就是通过DeviceControlActivity类传过来的蓝牙ID建立蓝牙连接
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
其中里面有一个非常重要的类mGattCallback回调,这里面重写了几个方法
onConnectionStateChange()蓝牙连接状态改变的回调;
onServicesDiscovered()服务发现的回调在这个方法中可以建立蓝牙的连接
onCharacteristicRead()蓝牙的特征;
onCharacteristicChanged()Characteristic状态改变的回调
onCharacteristicWrite)()Characteristic写操作的结果回调:
这里说一下重点:通过上面的解释还是会知其然不知其所以然。
蓝牙读数据有两种方法:
一种是调用readCharacteristic()方法 开启读 ,一种是通过通知来读 setCharacteristicNotification方法;
通过uuid 读某个Characteristic
开启读
mBluetoothLeService.readCharacteristic(characteristic);
public void readCharacteristic(BluetoothGattCharacteristiccharacteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
如果成功,数据会在下面的方法回调中传进来
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
还可以通过通知的回调方法读取数据 这种方式不用手机去轮询地读设备上的数据。
//设置true为启用通知,false反之
setCharacteristicNotification(mNotifyCharacteristic, true);
有消息来后会回调方法
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
写数据就更简单了
通过UUID获取到BluetoothGattCharacteristic
BluetoothGattCharacteristic alertLevel =linkLossService.getCharacteristic(UUID.fromString("49535343-8841-43f4-a8d4-ecbe34729bb3"));
alertLevel.setValue(values_on);
status = mBluetoothGatt.writeCharacteristic(alertLevel);
status如果为true,表示写操作已经成功执行,BluetoothGattCallback抽象类的一个方法会被执行,如果刚好你又重写了这个方法,就可以打印一些消息了
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristiccharacteristic, int status){
}
官方的demo没有用发送数据的代码,接收数据也是16进制,这个需要自己按实际情况修改代码或是在网上找一些demo有收发功能的,开放项目复杂多变,这里很难以偏概全,就不一一展示了;
总结:蓝牙收发数据每次最多20个字节,这就要对接收的数据进行拼接,截取了;发送数据也是以20个字节为单位,一段一段发送;蓝牙对于有些人来说也许会很难, 但是琢磨久了就会看懂的;