EXPT_1:E1BleTemperatureNodeActivity

目录

一、BLE开发流程 

二、E1BleTemperatureNodeActivity实现的功能

三、函数结构。

四、 函数具体介绍

1.getExtractData()

 2.initViews()

3. initBLuetooth()

①判断是否支持蓝牙

 ②判断系统蓝牙是否启动

4.connectBleDevice()

5. BluetoothGattCallback回调对象及其重写的函数

 

一、BLE开发流程 

BLE的开发流程基本上如下图所示,先判断是否支持,在判断是否打开,而后根据address建立Gatt连接实例,重写回调对象的方法负责监听蓝牙的状态变化以实现不同的功能。

  

使用到的API:

BluetoothManager

        官方文档:BluetoothManager  |  Android Developers

        蓝牙管理器,主要用于获取蓝牙适配器和管理所有和蓝牙相关的东西。

        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

BluetoothAdapter

        官方文档:BluetoothAdapter  |  Android Developers
        本地蓝牙适配器,用于一些蓝牙的基本操作,主要完成三方面的功能:a.开关蓝牙设备  b.扫描蓝牙设备  c.获取蓝牙设备的状态信息(name或address)。

//        BluetoothManager.getAdapter()方法获取此设备的默认BLUETOOTH适配器
        this.mBluetoothAdapter = bluetoothManager.getAdapter();

BluetoothDevice

        官方文档:BluetoothDevice  |  Android Developers
        蓝牙设备对象,代表一个具体的蓝牙外设,包含一些蓝牙设备的属性,比如设备名称、mac地址等。由BluetoothAdapter对象传入蓝牙外设的address才能实例化对应address的BluetoothDevice对象。

//      一个BluetoothGatt对应一个BluetoothGattCallback对象,而BluetoothDevice对象的获取只能靠BluetoothAdapter.getRemoteDevice(address)来获取
//      这的remoteDevice就代表一个蓝牙外设
            BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(address);

BluetoothGatt

        官网文档:BluetoothGatt  |  Android Developers
        蓝牙通用属性协议,定义了BLE通讯的基本规则,是BluetoothProfile的实现类,Gatt是Generic Attribute Profile的缩写,用于连接设备、搜索设备可提供的Service等操作,连接是要传入BluetoothGattCallback对象,并重写一些方法。

//      获取到BluetoothDevice之后就通过BluetoothDevice的connectGatt方法获取类似于socket的BluetoothGatt对象
            mRemoteBluetoothGatt = remoteDevice.connectGatt(this, false, bluetoothGattCallback);

BluetoothGattCallback

        官方文档:BluetoothGattCallback  |  Android Developers (google.cn)
        重写一些方法以完成我们需要的一些自定义功能。蓝牙设备连接成功后,用于回调一些操作的结果,必须连接成功后才会回调。

        他是所有蓝牙数据回调的处理者,也是整个蓝牙操作当中最为核心的一部分。它里面有很多方法,但并非所有都需要在开发当中用到,这里列出来只是作为部分解析,需要哪个方法,就重写哪个方法,不需要的,直接去掉。

        方法的功能和调用顺序可见:BluetoothGattCallback  |  Android Developers (google.cn)

private BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
    
@Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
         //侦测蓝牙连接状态的函数,在这些回调函数中应该是第一个被调用的
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        //当发现设备服务时,会回调到此处,下面是遍历所有发现的服务
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        //读取特征后回调到此处。
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        //写入特征后回调到此处,status == BluetoothGatt.GATT_SUCCESS代表写入成功
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        //当特征(值)发生变化时回调到此处。
    }

    @Override
    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        //读取描述符后回调到此处。
    }

    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        //写入描述符后回调到此处
    }

    @Override
    public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
        //暂时没有用过。
    }

    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        //Rssi表示设备与中心的信号强度,发生变化时回调到此处。
    }

    @Override
    public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
        //暂时没有用过。
    }
};

BluetoothProfile

        官方文档:BluetoothProfile - Android中文版 - API参考文档 (apiref.com)
        一个通用的蓝牙规范,设备之间按照这个规范来收发数据,在我们的比赛中,会用到他里面的一些状态常量判断蓝牙的连接状态。

 //BluetoothProfile的STATE_CONNECTED常量表示该配置文件处于连接状态,也就是蓝牙连接成功.
                //参考https://www.apiref.com/android-zh/android/bluetooth/BluetoothProfile.html
                /**
                 * 连接状态:
                 *    * The profile is in disconnected state   *public static final int STATE_DISCONNECTED  = 0;
                 *    * The profile is in connecting state     *public static final int STATE_CONNECTING    = 1;
                 *    * The profile is in connected state      *public static final int STATE_CONNECTED    = 2;
                 *    * The profile is in disconnecting state  *public static final int STATE_DISCONNECTING = 3;
                 *
                 */

BluetoothGattService
        蓝牙设备提供的服务,是蓝牙设备特征Characteristic的集合。

BluetoothGattCharacteristic
        感觉名字有点不太适合,他是承载GATT数据传输服务的基本数据单元,通信时候的数据就打包在里面。

BluetoothGattDescriptor

        官方文档:BluetoothGattDescriptor - Android中文版 - API参考文档 (apiref.com)
        蓝牙设备特征描述符,是对特征Characteristic的额外描述。

二、E1BleTemperatureNodeActivity实现的功能

        ①、描绘、更新显示温湿度的页面B。

        ②、负责蓝牙BLE的连接、数据解析与命令发送。

三、函数结构。

一共包含:11个方法,还包括一个BluetoothGattCallback回调对象,其中重写了四个方法。除此之外还有一个Thread对象,也重写了一个线程方法,总的来说是11+4+1=16个方法。

函数的大致作用以及调用关系如下图所示。

四、 函数具体介绍

1.getExtractData()

用于联系BleDeviceActivity页面和E1BleTemperatureNodeActivity页面。完成两个页面之间的数据(蓝牙name和address)传输。

    private void getExtraData() {
//        getIntent()方法:获得启动当前Activity时的Intent内容。
//        其实不难理解:在这个蓝牙温湿度的程序中,其实有两个页面:
//              一个是搜索、展示蓝牙的页面(BLeDeviceListActivity)。在这个页面会以一个自定义的ForBleAdapter展示ListView蓝牙设备信息列表。
//                  用户在诸多蓝牙设备中选择自己相连接的设备,然后通过下面的函数(见BleDeviceListActivity的85-93行)将选定的蓝牙信息打包成intent发送至第二个页面
//        第二个页面也就是选定蓝牙后与其建立通信的页面(E1BleTemperatureNodeActivity.java),下面的函数就是监听用户的点击,然后携带对应的蓝牙设备name和address跳转到第二个页面
//        this.mDeviceListView.setOnItemClickListener(new OnItemClickListener() {  //监听事件,监听用户点击的蓝牙ListView的哪个Item,然后将对应的蓝牙设备信息打包发送至下一个即将启动的页面
//            @Override
//            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//                Intent intent = new Intent(BleDeviceListActivity.this, E1BleTemperatureNodeActivity.class);
//                intent.putExtra("name", mBleDevices.get(position).getName());
//                intent.putExtra("address", mBleDevices.get(position).getAddress());
//                startActivity(intent);  //由new Intent(BleDeviceListActivity.this, E1BleTemperatureNodeActivity.class)可知会启动E1BleTemperatureNodeActivity页面
//            }
//        }

//        第二个页面启动后会通过getIntent方法获取上一个页面(BleDeviceListActivity)传入的Intent对象
//        而这个给Intent对象中包含着需要连接的蓝牙的name与Address
        this.mRemoteDevName = getIntent().getStringExtra("name");
        this.mRemoteDevAddress = getIntent().getStringExtra("address");
    }

 2.initViews()

①标题栏TitleBar控件初始化。

②监听事件的设置。

③温湿度节点展示框的绑定。

  /**
     * 控件初始化
     */
    private void initViews() {
//①标题栏TitleBar控件初始化。
        initTitleBar();
//③温湿度节点展示框的绑定。
        this.mRealTemperatureTv = (TextView) findViewById(R.id.realTemperature);
        this.mRealHumidityTv = (TextView) findViewById(R.id.realHumidity);
    }

    /**
     * 初始化标题栏.TitleBar从左到右依次是 ImageView 、 TextView 、 ToggleButton
     */
    private void initTitleBar() {
        mImageView = (ImageView) findViewById(R.id.backImageView);
        mImageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mConnectionState) {
                    showDisconnectBleDialog();
                } else {
//                    用于结束一个Activity的声明周期,举一个例子
//                    Activity1-》Activity2-》Activity3
//                    当第二步跳转时加finish()时候,在Activity3点击返回直接就到Activity1,不经过activity2,因为Activity2已经被销毁
//                    若第二部跳转不加finish()时候,在Activity3点击返回就返回到Activity2
                    finish();

//                    关于android中finish与OnDestory()的区别:
//                    finish会调用onDestory方法。调用Activity.finish()的时候,系统只是将最上面的Activity出栈。因此你点击back键,再也找不到这个Activity
//                    而调用onDestory的时候,会将当前的占用的资源全部删除。当再次重新进入这个页面的时候,必须重新创建,执行onCreate()方法
                }
            }
        });
//        TextView类型的mTitleTextView对象用于展示蓝牙设备的deviceName
        this.mTitleTextView = (TextView) findViewById(R.id.deviceName);
        this.mTitleTextView.setText(this.mRemoteDevName);

//        ToggleButton类型的mConnectRemoteDeviceBtn为连接/断开的按钮。用来连接蓝牙设备
        this.mConnectRemoteDeviceBtn = (ToggleButton) findViewById(R.id.connectBleBtn);
        this.mConnectRemoteDeviceBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // TODO Auto-generated method stub
                if (isChecked) {  //要是点击的话isChecked就是true
                    connectBleDevice(true, mRemoteDevAddress);
                } else {
                    connectBleDevice(false, "");
                }
            }
        });
    }

    /*
        第二步initTitleBar()调用的子函数:显示断开连接的那个弹出框。
    * */
    private void showDisconnectBleDialog() {
        AlertDialog.Builder dialogBuild = new AlertDialog.Builder(this);
        dialogBuild.setMessage("蓝牙已连接,确定断开?");

        //        1.设置正向按钮
        dialogBuild.setPositiveButton("断开连接", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                connectBleDevice(false, "");
                finish();
            }
        });

        //        2.设置负向按钮
        dialogBuild.setNegativeButton("再想想", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });

        //        3.create()一个对象并且.show()调用
        AlertDialog alertDialog = dialogBuild.create();
        alertDialog.show();
    }

3. initBLuetooth()

完成两个功能:

        ①、判断设备是否支持蓝牙功能

        ②、向用户申请开启蓝牙权限。

①判断是否支持蓝牙

   /**
     * 初始化蓝牙适配器,获取设备是否支持蓝牙,
     * 通过Boolean mSupportedBLE的参数值来判断
     */
    private void initBluetoothAdapter() {
//  创建第一个对象BluetoothManager,这个对象由调用系统服务getsystemService(Context.BLUETOOTH_SERVICE)来产生
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
//        拿到之后就是BluetoothAdapter,这个对象通过BluetoothManager.getAdapter()方法获得
        this.mBluetoothAdapter = bluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "设备不支持蓝牙功能", Toast.LENGTH_LONG).show();
        } else {
            mSupportedBLE = true;
        }
    }

 ②判断系统蓝牙是否启动

    /**
     * 判断系统蓝牙是否启用
     */
    private void enableBluetooth() {
        if (mSupportedBLE) {
//            如果支持蓝牙,则跳转到打开蓝牙的提示框
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivity(intent);
        }
    }

4.connectBleDevice()

那我们如何建立GATT连接以及如何读取Characteristic下的数据呢?
 * 1.通过BluetoothAdapter获取制定蓝牙设备的BluetoothDevice实例。(在本程序中指的是mRemoteDevice)
 * 2.建立GATT连接。使用步骤1中获取的设备实例,调用其connectGatt函数建立连接,再这一步需要传入重写的BluetoothGattCallback实例
 * 3.重写GattCallback回调。第二步建立GATT连接时,需要传入BluetoothGattCallback实例,因此我们得先实例一个BluetoothGattCallback类,并且重写其回调函数
 * 4.若GATT连接成功,onConnectionStateChange()函数回调。GATT成功或失败,会回调GattCallback下的onConnectionStateChange()函数,接下来会调用mBluetoothGatt.discoverServices()函数。功能是查询已连接的GATT下的service。
 * 5.onServicesDiscovered()方法回调,获取制定的Service和Characteristic,上一步调用BluetoothGatt.discoverServices()后,系统会回调GattCallback下的onServicesDiscovered()函数,这表明我们已经可以通过指定的UUID来获取指定的Service实例了
 * 在onServicesDiscovered()函数回调后,通过UUID先获取service,然后再使用获取到的service和UUID获取Characteristic,最后mBluetoothGatt.readCharacteristic(mVIDPIDCharacteristic);读取这个Characteristic
 * 6.onCharacteristicRead()函数回调,读取Characteristic的value值,上一步调用readCharacteristic()后,系统会回调gattCallback下的onCharacteristicRead(),此时我们使用回参characteristic直接getValue()即可读取到数值

    /**
     * 实际建立与BLE设备通信联系的客户端的就是这个函数。
     * 其实也不仅仅是这个函数,他传入的bluetoothGattCallback回调对象会重写并使用四个功能函数,
     *
     * @param address 设备地址:String类型
     *                传入true:进行连接
     *                传入false:进行断开
     */
    private void connectBleDevice(boolean connect, String address) {
        if (mBluetoothAdapter == null) {
            return;
        }
        if (connect) {  //如果传入true,则为要求连接
//      一个BluetoothGatt对应一个BluetoothGattCallback对象,而BluetoothDevice对象的获取只能靠BluetoothAdapter.getRemoteDevice(address)来获取
            BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(address);
//      获取到BluetoothDevice之后就通过BluetoothDevice的connectGatt方法获取类似于socket的BluetoothGatt对象
            mRemoteBluetoothGatt = remoteDevice.connectGatt(this, false, bluetoothGattCallback);
        } else {        //如果传入false,则为要求断开
            if (mRemoteBluetoothGatt != null) {
//      disconnect()断开已建立的连接,或取消当前正在进行的连接尝试,
                mRemoteBluetoothGatt.disconnect();
            }
        }
    }

5. BluetoothGattCallback回调对象及其重写的函数

数据交互全靠该回调对象重写的方法。但是重写什么方法,各个方法都是干什么用的。参考官方文档:BluetoothGattCallback  |  Android Developers (google.cn)

以及:(23条消息) Android 低功耗蓝牙开发(数据交互)_初学者-Study的博客-CSDN博客_android低功耗蓝牙开发

    /*
        下面的BluetoothGattCallback对象是供mRemoteBluetoothGatt = remoteDevice.connectGatt(this, false, bluetoothGattCallback)回调用的
    里面主要就是一个onConnectionStateChange函数,根据连接成功与否有相应的操作
        若成功: 调用BluetoothGatt的discoverServices方法。查询已经连接的Gatt支持的Service。
    而后会调用onServicesDiscovered()方法,在那个方法里面表面我们已经可以通过指定的UUID来获取指定的Service实例了,然后获取Characteristic和Descriptor。
    * */
    private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        //  不止这一个函数,下面四个函数都是包含在bluetoothGattCallback对象里面的,BluetoothGattCallback对象需要重写很多方法,
        //  本来的都没加@Override,其实加上更好,更容易让人看出来这是个重写的方法,并且编辑器也可以为我们检查一下是否重写正确,但是不加@Override也可以正常识别,因为JM会自动识别重写的函数,但是因为有的没重写对会导致识别不到重写的函数,因此还是加上@Override比较好
        //  而且不需要super调用父类函数(只有需要调用父类函数的时候再写super)

        /*
            在这四个函数中,这个函数是首先被调用的函数,类似于启动的初始化函数。
            很明显这个是对蓝牙连接状态的回调查看蓝牙是否连接成功。
        * */
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
//            这个newState参考的是BluetoothProfile的Constant
            switch (newState) {
                //BluetoothProfile的STATE_CONNECTED常量表示该配置文件处于连接状态,也就是蓝牙连接成功.
                //参考https://www.apiref.com/android-zh/android/bluetooth/BluetoothProfile.html
                /**
                 * 连接状态:
                 *    * The profile is in disconnected state   *public static final int STATE_DISCONNECTED  = 0;
                 *    * The profile is in connecting state     *public static final int STATE_CONNECTING    = 1;
                 *    * The profile is in connected state      *public static final int STATE_CONNECTED    = 2;
                 *    * The profile is in disconnecting state  *public static final int STATE_DISCONNECTING = 3;
                 *
                 */
                case BluetoothProfile.STATE_CONNECTED:
                    Log.e(TAG, "设备连接成功,开始发现设备服务。");
                    //  下面的函数很有必要,他的目的是让我们第二个重写的方法->OnServicesDiscovered显示所有的Services
                    gatt.discoverServices();
                    mConnectionState = true;
                    break;
                case BluetoothProfile.STATE_DISCONNECTED: {//STATE_DISCONNECTED常量表示配置文件处于断开状态
                    Log.e(TAG, "设备连接已断开");
                    mConnectionState = false;
                }
                default:
                    break;
            }
        }

        /*
         * 通过Gatt.discoverServices()设置触发。
         * 功能是:通过UUID获取制定的服务service,只获取大赛的实验箱的节点蓝牙服务,并且过滤掉无用的其他杂七杂八的蓝牙设备信号。
         * 这是发现服务的,不是发现蓝牙的,这时候蓝牙已经连接成功了。
         * 在这个回调中做的就是打开通知开关
         * */
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//      Step1:获取远程节点提供的服务,你可以将他理解为虚拟化的远程节点。
            BluetoothGattService remoteService = gatt.getService(UUID.fromString(Global.UUID_DS_SERVICE));
            if (remoteService != null) {
                Log.e(TAG, "发现大赛指定蓝牙GATT服务");
//      Step2:过滤只得到试验箱节点的Characteristic。
                mRemoteCharacteristic = remoteService.getCharacteristic(UUID.fromString(Global.UUID_DS_CHARACTERISTIC));
                if (mRemoteCharacteristic != null) {
                    Log.e(TAG, "发现大赛指定蓝牙GATT特征");
                    //设置通知。
                    BluetoothGattDescriptor descriptor = mRemoteCharacteristic.getDescriptor(UUID.fromString(Global.UUID_DS_DESCRIPTOR));
                    if (descriptor != null) {
                        //配置本地通知,为什么要配置本地通知?那什么又是本地通知呢?
                        //我们这个实验要求实时更新BLE的特征变化,那我们就得在特征变化时收到通知才行,我们用Gatt的setCharacteristicNotification()为我们选中的特征启动通知
                        //一旦该特征Characteristic在节点上发生变化(也就是温湿度发生变化),就会触发onCharacteristicisChanged()函数回调
                        //而就我们这个实验来讲,我们把解析温湿度数据以及实时更新UI的函数写在onCharacteristicisChanged函数中了,
                        // 通过这样就实现了我们这个实验的目的:实时检测温湿度变化并更新UI显示
                        gatt.setCharacteristicNotification(mRemoteCharacteristic, true);


                        // 配置远程。
                        // descriptor.setValue()用来将本地的descriptor存储的值更新
                        // ENABLE_NOTIFICATION_VALUE:用于启动客户端配置描述符
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

                        //将给定的描述符写入关联的远程设备
                        //为onDescriptorWrite()设置触发回调,需要传入BluetoothGattDescriptor对象
                        gatt.writeDescriptor(descriptor);
                    } else {
                        Log.e(TAG, "没有发现大赛指定GATT描述");
                    }
                } else {
                    Log.e(TAG, "没有发现大赛指定蓝牙GATT特征");
                }
            } else {
                Log.e(TAG, "没有发现大赛指定的蓝牙GATT服务");
            }
        }


        //   描述符写入回调,由gatt.writeDescriptor(descriptor)设置回调
        //   这部分函数作用是:启动一个线程,线程循环向温湿度节点发送读取命令,间隔两秒。
        //   注意一个误区:我们发送的读取命令是打包在Characteristic中的发送的,而非放在Descriptor里面的(mRemoteCharacteristic.setValue(Read_CMD_Bytes);)
        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            Log.e(TAG, "Gatt通知已设置:" + descriptor.getUuid().toString());
            //  启动数据发送线程
            if (!isReadRunning) {
                isReadRunning = true;
//                mReadTheThread线程重写的run()方法中包含发送数据的操作
                mReadTheThread.start();
            }
        }

        /*
            下面这个函数是用来解析节点返回的数据,当特征发生变化时候自动触发调用
            见https://www.apiref.com/android-zh/android/bluetooth/BluetoothGattCharacteristic.html官方API
            当Cahracteristic发生变化的时候调用。
        * */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.e(TAG, "onCharacteristicChanged : " + ByteUtils.bytes2HexString(characteristic.getValue()));
            //01 03 04
            //01 FF 湿度计算:(01 * 256) + 0xFF = 511, 则湿度的实际值为51.1RH%
            //00 FF 温度计算:(00 * 256) + 0xFF = 255,则温度的实际值为25.5℃
            //8b bf
            if (characteristic.getValue().length == 9) {
                final float mRealHumidityFloat = (float) ((characteristic.getValue()[3] & 0xff) * 256 + (characteristic.getValue()[4] & 0xff)) / 10;
                final float mRealTempturatureFloat = (float) ((characteristic.getValue()[5] & 0xff) * 256 + (characteristic.getValue()[6] & 0xff)) / 10;
                // runOnUiThread是android自带的方法:用于更新应用UI,不能什么都放到主线程里面,主线程很忙的,既要处理绘制UI,响应用户的交互等
                // 将UI的更新任务放到工作线程之外的线程,有助于获得更流畅的用户体验,避免无响应(也就是卡死情况)的发生。
                // 还涉及到handle和looper的知识,这里不赘述了。
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mRealHumidityTv.setText(String.valueOf(mRealHumidityFloat));
                        mRealTemperatureTv.setText(String.valueOf(mRealTempturatureFloat));
                    }
                });
            }
        }
    };

   /**
     * 写命令到远程BLE设备
     * 不属于BluetoothCallback中要重写的函数,但是Callback却用到了下面这个函数来发送命令。
     *
     * @param bytes 数据
     */
    private void writeGattCharacteristic(byte[] bytes) {
        if (mRemoteCharacteristic != null) {
            Log.e(TAG, "发送数据 " + ByteUtils.bytes2HexString(bytes));
            mRemoteCharacteristic.setValue(bytes);
            mRemoteBluetoothGatt.writeCharacteristic(mRemoteCharacteristic);
        }
    }


    //这个线程用来发送命令:每2s发送一次命令:
    private Thread mReadTheThread = new Thread() {
        public void run() {
            while (mConnectionState) {
                writeGattCharacteristic(READ_BLE_CMD);
                try {
                    sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    };

学习参考:

官方文档:https://developer.android.google.cn/reference/android/

Android bluetooth创建GATT连接并读取设备信息 - 简书 (jianshu.com)

低功耗蓝牙Ble的详细使用流程 - 简书 (jianshu.com)

(23条消息) Android 低功耗蓝牙开发(数据交互)_初学者-Study的博客-CSDN博客_android低功耗蓝牙开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ad_m1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值