网上关于BLE编程,都是通过Service来进行的,但我写的简单实例,是通过子线程来进行连接获得characteristic,虽然会存在一些问题,
但仅供BLE部分学习的参考与理解应该还是有帮助的。下面通过代码来逐一分析BLE编程的流程,以及注意的事项。
/*
程序的总体思路:
1:先判断本地设备是否支持BLE功能,如果支持则打开设备BLE,否则退出
2:打开本地BLE后,依据MAC(远程设备的MAC地址)获得BluetoothDevice(远程BLE设备实例)
3:依据获得的设备建立连接,获得BluetoothGatt对象,此中会自动回调一些方法,在回调方法中可以实现某些操作
4:根据characteristic实现数据接发的传输
*/
注意:BLE中characteristic是数据接发的“基本单位”,我们需要通过MAC地址连接到蓝牙模块,通过UUID获得两者characteristic
对characteristic操作来实现数据的接发。这里MAC地址是通过广播的形式抓取到的,在后续博客中我将更加完善的说明,UUID一般蓝牙模块文档会提供。
package com.example.administrator.bluetooth42;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class MainActivity extends AppCompatActivity {
/* 定义布局中控件变量 */
private Button connect;
private Button send;
private Button received;
private TextView text;
private BluetoothManager bluetoothManager; // 定义系统蓝牙管理器
private BluetoothAdapter bluetoothAdapter; // 定义本地蓝牙实例
private BluetoothDevice bluetoothDevice; // 定义远程蓝牙实例
private BluetoothGatt bluetoothGatt; // 定义蓝牙连接成功的BluetoothGatt对象,用于获取接发封装的信息
// 定义一个泛型List,用于获取连接后产生的service
private List<BluetoothGattService> bluetoothGattServices = new ArrayList<BluetoothGattService>();
/* 在BLE中,通信与传统Bluetooth是有区别的,不是根据MAC和UUID采用类Socket的方法
BLE中,接发信息是存在characteristic中的,其为数据接发的直接操作载体(完成BLE的基本单位)
BLE编程,首先根据MAC地址建立连接,通过回调方法,获取service(一般有多个),通过service获得characteristic(一个service也可以含有多个)
characteristic中则包含value或Descriptor。我们需要的是具有接发功能的characteristic(根据UUID获得)
*/
private final String address = "20:91:48:31:2B:CD"; // MAC地址
private final String uuid="0000ffe1-0000-1000-8000-00805f9b34fb";
// Android中是不能在子线程中进行View更新的,需要将更新信息返回主线程,在主线程中操作,这里一般采用Handler Message的方式
private Handler handler = new Handler() // 获得子线程或回调方法发送的消息,一般用于主线程View的处理更新
{
@Override
public void handleMessage(Message msg)
{
String str = (String)msg.obj;
text.setText(str); // 将数据转化为String,在界面中显示出来
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connect = (Button)findViewById(R.id.connect);
send = (Button)findViewById(R.id.send);
received = (Button)findViewById(R.id.received);
text = (TextView)findViewById(R.id.text);
View.OnClickListener listener = new View.OnClickListener()
{ // 时间监听器,根据ID值,判断是点击了哪个按钮
@Override
public void onClick(View v)
{
switch(v.getId())
{
case R.id.connect : Connect();break;
case R.id.send : Send();break;
case R.id.received : Received();break;
}
}
};
connect.setOnClickListener(listener);
send.setOnClickListener(listener);
received.setOnClickListener(listener);
InitBluetooth();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void InitBluetooth() { // 初始化本地蓝牙设备
bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter==null || !bluetoothAdapter.isEnabled())
{
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,1);
}
}
// 在获得BluetoothGatt对象进行操作时,就会调用这里面的某些方法
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override //设备连接成功并回调该方法
public void onConnectionStateChange(BluetoothGatt gatt, int status,final int newState) {
// super.onConnectionStateChange(gatt,status,newState);
runOnUiThread(new Runnable(){
@Override
public void run()
{
switch(newState)
{
case BluetoothGatt.STATE_CONNECTED:
System.out.println("......Hello......");
bluetoothGatt.discoverServices(); // 连接成功后查询该设备的服务
break;
//正在连接
case BluetoothGatt.STATE_CONNECTING:
break;
//连接断开
case BluetoothGatt.STATE_DISCONNECTED:
break;
//正在断开
case BluetoothGatt.STATE_DISCONNECTING:
break;
}
}
});
}
@Override // 发现服务后回调该方法
public void onServicesDiscovered(BluetoothGatt gatt,int status)
{
//super.onServicesDiscovered(gatt,status);
if(status==bluetoothGatt.GATT_SUCCESS)
{
System.out.println("下面开始获得服务!");
bluetoothGattServices = gatt.getServices(); // 获得所有的Service
if(bluetoothGattServices.size()==0)
{
System.out.println("服务列表为空!");
}
}
}
@Override // 当读取设备时,会回调该函数
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,int status)
{
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] mByte = characteristic.getValue();
Message msg = new Message(); // 这里使用了一个消息机制,将信息返回主线程,在回调方法和子线程中是不允许进行View更新的
System.out.println("......"+mByte.length+".......");
System.out.println("......"+mByte[0]+".....");
String res = new String(mByte);
System.out.println("++++"+res+"------");
msg.obj = res;
handler.sendMessage(msg);
}catch(Exception e)
{
System.out.println("抛出异常!");
}
} /** end of if (status == BluetoothGatt.GATT_SUCCESS) */
System.out.println("aoaoaoaoaoao");
} @Override // 设备发出通知时会调用到该接口
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic)
{
byte[] mByte = characteristic.getValue();
StringBuilder mStrBuilder = new StringBuilder(mByte.length);
/** 逐byte转换 */
for (byte mByteChar : mByte) {
mStrBuilder.append(String.format("%02x", mByteChar));
} /** end of for (byte mByteChar : mByte) */
System.out.println("bcbcbcbcbcbco");
}
@Override
public void onCharacteristicWrite(final BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic,int status) {
//super.onCharacteristicWrite(gatt, characteristic, status);
System.out.println("发送数据成功!");
if(status==BluetoothGatt.GATT_SUCCESS)
{
try
{
byte[] mByte = characteristic.getValue();
StringBuilder mStrBuilder = new StringBuilder(mByte.length);
for (byte mByteChar : mByte) {
mStrBuilder.append(String.format("%02x", mByteChar));
System.out.println("222000");
}
}catch (Exception e) {
System.out.println("111000");
e.printStackTrace();
}
}
System.out.println("dddeeeddedede");
}
};
private void Connect() {
/* 这里的MAC地址是通过广播的形式,抓取到的,为了便于说明,这里直接使用了,省略了相应代码 */
// BLE 的MAC地址一般是唯一的
bluetoothDevice = bluetoothAdapter.getRemoteDevice(address); // 通过MAC地址,获得远程设备实例
bluetoothGatt = bluetoothDevice.connectGatt(this,false,mGattCallback);
System.out.println("建立连接成功!");
}
private void Received() { // 接收按钮执行的事件监听函数
System.out.println("执行接收函数!");
// 开启一个子线程,通过characteristic实现从BLE接收数据
runOnUiThread(new Runnable() {
@Override
public void run()
{
for(BluetoothGattService GattService : bluetoothGattServices)
{
List<BluetoothGattCharacteristic> bluetoothGattCharacteristics = GattService.getCharacteristics();
for(BluetoothGattCharacteristic characteristic : bluetoothGattCharacteristics)
{ //接收与发送是一样的道理,不过这里是获得characteristic,在回调方法中操作结果
if(characteristic.getUuid().toString().equals(uuid))
{
System.out.println("lisajjashaJ"); // 在会调方法中执行读取数据的显示工作
bluetoothGatt.readCharacteristic(characteristic); // 获得接收的数据载体characteristic,成功后会回调onCharacteristicRead方法
System.out.println("等待回调接收相应方法!");
}
}
}
}
});
}
private void Send() { // 发送按钮点击后执行的函数:
System.out.println("执行发送函数");
// 开启一个子线程用于通过获得的characteristic发送数据至远程BLE设备
runOnUiThread(new Runnable(){
@Override
public void run()
{
for(BluetoothGattService GattService : bluetoothGattServices)
{ // 遍历Service数组,获得该服务中的characteristic
List<BluetoothGattCharacteristic> bluetoothGattCharacteristics = GattService.getCharacteristics();
for(BluetoothGattCharacteristic characteristic : bluetoothGattCharacteristics)
{ // 遍历service对应的characteristic,看是否具有用于收发的characteristic
// 其实每个service,characteristic,descriptor都有一个对应的UUID
if(characteristic.getUuid().toString().equals(uuid))
{
byte[] sum = {(byte)0x00};
System.out.println("Lalalalala");
characteristic.setValue(sum); // 设置要发送的characteristic,为其赋予值,它像个载体
bluetoothGatt.writeCharacteristic(characteristic); // 此方法执行会回调onCharacteristicWrite方法
System.out.println("等待回调发送信息函数是否成功");
}
}
}
}
});
}
}/*
先获得Service,再获得需要的characteristic,利用characteristic来进行数据操作。
在characteristic进行数据接发后,会调用BluetoothGattCallback 中重载的相应方法。
*/
第一篇博客,不足之处还请多多包涵。写博客一来是想记录,梳理自己所学的东西,二来是想和大家多多分享交流。
不足之处,或是有错误还望留言指正,谢谢。