---恢复内容开始---

## 前言
孤芳自赏,一揽芳华;
人情冷暖,自在人心;
登高远眺,望步止前;
喜笑言开,欺人骗己。
上篇文章介绍了基本的蓝牙使用,书写的demo也不是很完善,希望各位大神能够改正。这两周由于公司开发的进度,还有个人的一些原因,没有及时写这篇文章来介绍我写的这个demo。这是对自己的一种不负责。这两周,boss让我按照OCP原则重构代码,改了一遍有一遍,到后来还是boss给我弄了个demo参照着并帮助我把代码重构完毕。对于面向对象的三大特征,六大原则,二十三种设计模式,这里我就不显丑了,等我把书看完在一 一介绍。

正文

一、打开蓝牙并扫描蓝牙设备

private void initBluetoothAdapter() {
if (null == mBluetoothManager) {
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);// 获取系统服务
if (null != mBluetoothManager) {
mBluetoothAdapter = mBluetoothManager.getAdapter();//获得蓝牙适配器(Adapter)
}
} if (null == mBluetoothAdapter) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//以防Manager为null,再次获取蓝牙适配器
if (null == mBluetoothAdapter) {
Toast.makeText(this, R.string.noBluetooth, Toast.LENGTH_SHORT).show();
return;
}
}
//查看手机是否打开了蓝牙,如果没有打开,提示用户打开蓝牙
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
}
}
}

蓝牙打开后就是扫描蓝牙设备,发现蓝牙了

if (null != mBluetoothAdapter)
mBluetoothAdapter.startDiscovery();//扫描蓝牙

这时需要注册下Receiver,接收发现蓝牙的信息

private void register() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//扫描到蓝牙设备注册的action
intentFilter.addAction(BluetoothConstant.ACTION_DATA_AVAILABLE);//蓝牙启动后,返回数据时的监听
intentFilter.addAction(BluetoothConstant.ACTION_DATA_COMPLETE);//蓝牙数据返回完成后,最后返回的数据
registerReceiver(mBroadcastReceiver, intentFilter);
}
  • 对扫描到的蓝牙进行处理,把需要的蓝牙的名字保存下来,并链接Service,在Service中对蓝牙进行连接,并把一些给蓝牙写入命令,处理蓝牙回调的都放到Service中,减小Activity页面的开销。

二、链接蓝牙设备

在蓝牙中有一个至关重要的类——BluetoothGatt,他是对蓝牙进行操作的类,给蓝牙写入Write命令,Read命令,都需要用到它,他的初始化适合蓝牙链接密不可分的。

在Service中封装的方法,有一个是用来链接蓝牙的,并在这个方法中初始化BluetoothGatt。

/**
* 链接蓝牙
*
* @param address 蓝牙地址
* @return 链接是否成功
*/
public boolean connect(BluetoothAdapter bluetoothAdapter,String address) {
this.mBluetoothAdapter = bluetoothAdapter;
if (null == address || null == mBluetoothAdapter) {
Log.e(TAG, "connect Bluetooth address or BluetoothAdapter is null that not initial");
return false;
} if (mDeviceAddress != null && address.equals(mDeviceAddress)
&& mBluetoothGatt != null) {
//链接过的设备再次链接
Log.i(TAG, "connect existing device");
return mBluetoothGatt.connect();
}
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (null != device) {
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);//第一次链接蓝牙并初始化BluetoothGatt
mDeviceAddress = address;
this.mDeviceName = device.getName();
}else {
Log.i(TAG,"device is null");
}
return true;
}
  • 在链接蓝牙中又个坑,这个坑也不是每次出现,也不是每天出现,而是偶尔出现几次,那就是链接过的蓝牙,当你断开再次链接会链接不上,有时会显示扫描不到所有蓝牙设备,我没有很好的解决办法,临时办法就是关闭蓝牙,重新在进行蓝牙扫描并链接。

三、注册通道

对于蓝牙回调的一些方法和回调处理在上篇文章中已经大致写了一些,这里就不再详细的介绍了。

当蓝牙链接成功就需要扫描蓝牙的服务通道

mBluetoothGatt.discoverServices();

扫描到蓝牙服务后,遍历服务中的所有通道并选择你需要的通道进行注册。

/**
* 获取特征值(特征UUID) 用来做与蓝牙通讯的唯一通道
*
* @param gattServices BluetoothGattService
*/
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null)
return;
String uuid;
/**
*这里说一下,names,uuids,receiveUUIDs必须一 一对应(示例在下方),如果有不需要的用设备名称补气,如若为"" 程序可能出错,通道注册失败。
*/
String[] names = BluetoothConstant.getInstance().getDeviceNames();
String[] uuids = BluetoothConstant.getInstance().getNotificationUUIDs();
String[] receiveUUIDs = BluetoothConstant.getInstance().getReceiveNotificationUUIDs();
//从所有服务里面,找到能够和蓝牙通信的有效服务UUID
for (BluetoothGattService gattService : gattServices) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
//从服务中找到自己所需的特征值BluetoothGattCharacteristic
for (BluetoothGattCharacteristic characteristic : gattCharacteristics) {
uuid = characteristic.getUuid().toString();
String device = mBluetoothGatt.getDevice().getName();
for (int i = 0; i < names.length; i++) {
if (uuid.contains(uuids[i]) && device.equals(names[i])) {
//这里就是需要的特征值了
Log.i(TAG,">>>><<<<< \n name ="+names[i]+"\n"+"uuid = "+uuid+"\n"+"receiveUUID = "+receiveUUIDs[i]);
if (!uuid.contains(receiveUUIDs[i])) {
this.mCharacteristic = characteristic;//这里为什么要加一个if,是因为有的蓝牙数据返回和写入命令是一个通道;有的数据返回是一个通道,写入命令是另一个通道;当用返回数据的通道写入命令是,命令是写不进去的。所以,当不是蓝牙返回数据的通道时,把特征值全局化。
}
notification(characteristic);
}
}
}
}
}
//这里说一下,为什么这么写,刚开始注册通道的时候只写了mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true)一句,然而并不是每次都能注册成功的,在网上查找了几个方法,只有这个方法比较用,这样,通道就不会注册错误了。
private void notification(BluetoothGattCharacteristic gattCharacteristic) {
boolean success = mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true); Log.i(TAG,"notification characteristic permissions = "+gattCharacteristic.getPermissions()+"\n"
+"characteristic properties = "+ gattCharacteristic.getProperties()+"\n"+
"characteristic uuid = "+gattCharacteristic.getUuid());
if (success) {
for (BluetoothGattDescriptor dp : gattCharacteristic.getDescriptors()) {
if (dp != null) {
if ((gattCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
}
mBluetoothGatt.writeDescriptor(dp);
try {
Thread.sleep(200);//这里为什么会休眠200ms,是因为,注册速度太快,并不是所有的通道都能注册成功,加个延迟,会好些
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

下面是蓝牙的一些基本设置,写在了BluetoothConstant类中,这个类主要是统一写一些蓝牙相关的东西,例如名称,注册通道,接受数据的通道,命令等。

//设备名称
private final String[] deviceNames = new String[]{
DEVICE_NAME_ONE,
DEVICE_NAME_TWO,
DEVICE_NAME_TWO,
DEVICE_NAME_THREE
};
//需要注册蓝牙Characteristic的通道(读,写,通知)
private final String[] notificationUUIDs = new String[]{
"0001",
"0002",
"0003",
"0004"
};
//只接收数据的通道,不进行读写,不是UUID的是占位,占位的也可以是其他字符窜,只要不是""就可以。
private final String[] receiveNotificationUUIDs = new String[]{
"DEVICE_NAME_ONE",
"DEVICE_NAME_TWO",
"0000fff4-0000-1000-8000-00805f9b34fb",
"DEVICE_NAME_THREE"
};

对于隔了这么长时间才写这篇文章,我深感抱歉。在蓝牙开发中,最可恶的是蓝牙提供商,给了协议,但是没有具体命令,这需要我们自己去拼写命令,然而在命令的最后一位是校验位,有奇偶检验,有异或校验,有CRC8校验,有CRC16校验,这里我给大家提供福利,把这异或校验和CRC8校验记录下来:

/**
* 异或校验位计算
* 去掉起起始位,从第二位开始算
*/
private void getXOR(int[] hexs){
int xor = 0;
for (int i = 0;i<hexs.length;i++){
xor = xor^hexs[i];
Log.i(TAG,"XOR ="+xor);
}
Log.i(TAG,"Hex XOR = "+xor);
} // CRC8校验
private static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188, (byte) 226, (byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194, (byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253, (byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33, (byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30, (byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96, (byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159, (byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160, (byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128, (byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2, (byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61, (byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29, (byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24,
(byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155, (byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102, (byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219, (byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228, (byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251, (byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101, (byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184, (byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69, (byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248, (byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199, (byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134, (byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185, (byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237,
(byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242, (byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205, (byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112, (byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141, (byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14, (byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77, (byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109, (byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82, (byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142, (byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177, (byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145, (byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148, (byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23, (byte) 73, (byte) 8,
(byte) 86, (byte) 180, (byte) 234, (byte) 105, (byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235, (byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212, (byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244, (byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183, (byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52, (byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201, (byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116, (byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75, (byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10, (byte) 84, (byte) 215, (byte) 137, (byte) 107, 53 }; /**
* 计算数组的CRC8校验值
*
* @param data
* 需要计算的数组
* @return CRC8校验值
*/
public static byte calcCrc8(byte[] data) {
return calcCrc8(data, 0, data.length, (byte) 0);
} /**
* 计算CRC8校验值
*
* @param data
* 数据
* @param offset
* 起始位置
* @param len
* 长度
* @param preval
* 之前的校验值
* @return 校验值
*/
public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
byte ret = preval;
for (int i = offset; i < (offset + len); ++i) {
ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
}
return ret;
}

关于蓝牙开发的一些知识内容基本就介绍完了,如果有问题的同学,可以加QQ群:177694195 我们一起讨论蓝牙的开发。

---恢复内容结束---

Android开发——蓝牙的更多相关文章

  1. Android 开发 蓝牙开发

    前言 蓝牙开发其实分2个部分,一个是正常蓝牙功能的开发(比如Android蓝牙的互相连接.读取蓝牙列表.文件传输.蓝牙耳机等等).另外一个是BLE蓝牙开发(属于低功耗蓝牙设备,设备大多是血糖仪.蓝牙手 ...

  2. Android低功耗蓝牙(BLE)开发的一点感受

    最近一段时间,因为产品的需要我做了一个基于低功耗蓝牙设备的Android应用,其中碰到了一些困难,使我深深体会到Android开发的难处:不同品牌,不同型号和不同版本之间的差异使得Android应用适 ...

  3. 【视频】零基础学Android开发:蓝牙聊天室APP(四)

    零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...

  4. 【视频】零基础学Android开发:蓝牙聊天室APP(二)

    零基础学Android开发:蓝牙聊天室APP第二讲 2.1 课程内容应用场景 2.2 Android UI设计 2.3 组件布局:LinearLayout和RelativeLayout 2.4 Tex ...

  5. Android 串口蓝牙通信开发Java版本

    Android串口BLE蓝牙通信Java版 0. 导语 Qt on Android 蓝牙通信开发 我们都知道,在物联网中,BLE蓝牙是通信设备的关键设备.在传统的物联网应用中,无线WIFI.蓝牙和Zi ...

  6. 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体解释

    转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体 ...

  7. 【视频】零基础学Android开发:蓝牙聊天室APP(三)

    零基础学Android开发:蓝牙聊天室APP第三讲 3.1 ImageView.ImageButton控件具体解释 3.2 GridView控件具体解释 3.3 SimpleAdapter适配器具体解 ...

  8. 【视频】零基础学Android开发:蓝牙聊天室APP(一)

    零基础学Android开发:蓝牙聊天室APP第一讲 1. Android介绍与环境搭建:史上最高效Android入门学习 1.1 Google的大小战略 1.2 物联网与云计算 1.3 智能XX设备 ...

  9. Android Studio 蓝牙开发实例——基于Android 6.0

    因项目需要做一个Android 的蓝牙app来通过手机蓝牙传输数据以及控制飞行器,在此,我对这段时间里写的蓝牙app的代码进行知识梳理和出现错误的总结. 该应用的Compile Sdk Version ...

随机推荐

  1. Hackrank Equal DP

    Christy is interning at HackerRank. One day she has to distribute some chocolates to her colleagues. ...

  2. asp.net listview 实现分页浏览效果

    页面代码: <div style="margin-top:0px;">共<asp:Label ID="lb_count" runat=&quo ...

  3. USING REFLECTION

    In this section, you take a closer look at the System.Type class, which enables you to access inform ...

  4. 工作笔记——sqlserver引号的运用

    一. sqlserver引号问题:因为要使用远程连接,所以sql语句要用单引号括起来 SELECT * FROM OPENQUERY ([192.168.***.***] ,'select * fro ...

  5. 【SCOI 2005】 互不侵犯

    [题目链接] 点击打开链接 [算法] 和HDU2167类似 先搜出一行内符合的状态,然后,f[i][j][k]表示第i行,第j种状态,放了k个,合法的方案,DP即可 [代码] #include< ...

  6. MySql LOAD DATA 使用

    load的语法 LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE] INTO ...

  7. 简单粗暴解决google被和谐导致google fonts无法加载的问题

    原文:http://www.v2ex.com/t/118403 解决方法:fonts.googleapis.com替换为fonts.useso.com, fonts.useso.com是360安全卫士 ...

  8. PCB Web版SI9000阻抗计算器

    在几个月前写过一遍关于: PCB SI9000阻抗计算引擎Web方式实现方法  ,最近开始参考Polar SI9000的界面,将阻抗计算器转为网页版的方式实现.   一.Web版SI9000阻抗计算器 ...

  9. 点击button传递消息,但是页面不跳转的解决方法

    最近在做一个物联网的项目时遇到的问题:界面上有很多控制开/关灯的button,通过点击button来控制各个灯的亮灭.我需要将获取的不同的点击事件消息,以Socket通信的方式发送给硬件端的服务监听程 ...

  10. 洛谷 P4014 分配问题 【最小费用最大流+最大费用最大流】

    其实KM更快--但是这道题不卡,所以用了简单粗暴的费用流,建图非常简单,s向所有人连流量为1费用为0的边来限制流量,所有工作向t连流量为1费用为0的边,然后对应的人和工作连(i,j,1,cij),跑一 ...