网上关于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 中重载的相应方法。

*/

  第一篇博客,不足之处还请多多包涵。写博客一来是想记录,梳理自己所学的东西,二来是想和大家多多分享交流。


  不足之处,或是有错误还望留言指正,谢谢。