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

## 前言
孤芳自赏,一揽芳华;
人情冷暖,自在人心;
登高远眺,望步止前;
喜笑言开,欺人骗己。
上篇文章介绍了基本的蓝牙使用,书写的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. 硬件开发之bt输出---BT656/BT601/BT1120协议以及DM365/DM355/DM6467上使用的YUV颜色空间说明

    http://blog.csdn.net/zhouzhuan2008/article/details/17168133

  2. cocos2d-x中锚点设置及定位方式

    问题 在cocos2d演示样例代码HelloCpp中,为什么要将CCMenu设置位置到CCPointZero,即使CCMenu的锚点是在(0.5, 0.5)? 回答 这是由于CCMenu没有使用锚点进 ...

  3. [C#]从URL中获取路径的最简单方法-new Uri(url).AbsolutePath

    今天在写代码时遇到这样一个问题: 如何从字符串 "http://job.cnblogs.com/images/job_logo.gif" 中得到 "/images/job ...

  4. 【翻译自mos文章】在12c中Create or Truncate Table时非常慢,等待事件为 DFS Lock Handle wait

    来源于: Create or Truncate Table Slow in 12c While Waiting for DFS Lock Handle wait (文档 ID 2085308.1) A ...

  5. ZOJ 3962 E.Seven Segment Display / The 14th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple E.数位dp

    Seven Segment Display Time Limit: 1 Second      Memory Limit: 65536 KB A seven segment display, or s ...

  6. c中的变量

    1 变量类型 1.1 static global or static .data/.bss 1.2 automic stack,its relevant to os kernel and compil ...

  7. 笔试题:求第M个到第N个素数之间全部素数

    题目描写叙述 令Pi表示第i个素数. 现任给两个正整数M <= N <= 10000,请输出PM到PN的全部素数. 输入描写叙述: 输入在一行中给出M和N,其间以空格分隔. 输出描写叙述: ...

  8. Linux 杀死所有进程

    方法一: sudo killall -9 netease-cloud-music 这种方法,必须要写全称. sudo netease-cloud-music QStandardPaths: XDG_R ...

  9. [Usaco2015DEC] Breed Counting

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4397 [算法] 树状数组 时间复杂度 : O(QlogN) [代码] #includ ...

  10. 01_创建一个新的activity&activity配置清单文件

    今天开始学四大组件.今天是学Activity,然后是广播接收者,然后是服务,然后是内容提供者.四大组件,咱们一天一个.Activity就是跟用户交互的界面,大部分的应用都不会只有这么一个界面.创建多个 ...