Android完成BLE5.0低功耗蓝牙扫描界面与功能并读写数据

写在前面

    换工作之后新任务是做个Android的App,用Java写算是前期比较简单的一个工作了(现在突然被公司派去了图像处理也不多说了),目标是完成蓝牙扫描-连接-读写数据。

    要求只是一个Demo,对于线程方面要求不高,而且我也是第一次写Android,因此参考的话也可以后期进行自己的修改和整理。

    所有参考资料的网址都给了链接,在对于我逻辑阐述不到位的地方,可以点击参考链接参考前辈们的资料。

API

    安卓入门:https://www.runoob.com/w3cnote/android-tutorial-toast.html

    蓝牙API:https://www.php.cn/manual/view/15887.html ←点击该连接进入应该直接进入到Android的BlueDevice的相关参数

蓝牙基础配置:

    App的使用需要开启一些蓝牙的基础配置,在各个参考资料中也提到了。

   在项目包中找到AndroidManifest.xml,在里面直接添加蓝牙的基础配置。

   注:我的配置是android版本>6.0的,<6.0的话要去掉几个配置,但是现在感觉市面上也没有<6.0的版本了,如果做<6.0的版本可以单独搜一搜(我下面的一些参考连接中也会提到。

 <!-- 蓝牙权限 add by momo-->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH" /> <!-- 基于地理位置 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 不支持低功耗蓝牙的是否安装 -->
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="true" />
    <!-- 读写文件的权限 add by momo -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

 

蓝牙扫描界面

    参考链接:https://blog.csdn.net/qq_35270692/article/details/76359873 

    我的界面如图所示:

    

    界面代码(activity_bluetooth.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/layout_full"
    android:orientation="vertical">

    <LinearLayout
        style="@style/layout_vertical"
        android:layout_weight="12"
        android:orientation="horizontal">

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <Button
                android:id="@+id/startScale"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="开始扫描"
                app:backgroundTint="@color/startScale" />

            <Button
                android:id="@+id/stopScale"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="停止扫描"
                app:backgroundTint="@color/stopScale" />

            <Button
                android:id="@+id/startRead"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="开始读取"
                app:backgroundTint="@color/startRead" />

            <Button
                android:id="@+id/stopRead"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="停止读取"
                app:backgroundTint="@color/stopRead" />

            <ProgressBar
                android:id="@+id/progressbar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="stopScale" />

            <ListView
                android:id="@+id/listview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            </ListView>

        </LinearLayout>

    </LinearLayout>
</LinearLayout>

    color等一些参数可以自行设置

    

    创建界面内嵌的listview(layout_listview_item)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <TextView
        android:id="@+id/device_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="蓝牙设备名字"
        android:layout_margin="2dp"
        />
    <TextView
        android:id="@+id/device_address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="蓝牙设备的名字"
        android:layout_margin="5dp"
        />

    <TextView
        android:id="@+id/device_status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="蓝牙设备的状态" />

</LinearLayout>

 

蓝牙扫描功能

    参考连接1:https://blog.csdn.net/qq_39326574 ←这位前辈的博客里写了蓝牙的扫描和读写数据,是最为简单直白的,适合有较好基础的或者较为熟悉蓝牙的朋友学习。

    参考链接2:https://www.cnblogs.com/littlecarry/p/11889982.html ←这位前辈是从原理出发详解BLE扫描的基础,可以认真研读一下明白蓝牙收发的机制。

    知识点参考:获取当前链接的蓝牙设备

    知识点参考:Android检查设备连接状态

    知识点参考:Android : BluetoothAdapter.LeScanCallback

    知识点参考:蓝牙扫描 LeScanCallback 方法 不回调

    知识点参考:BLE的connect()和connectGatt的区别   

    -------------------------------------------------------------------------

    以上是我学习过程中受益匪浅的前辈资料,当遇到问题也许可以通过这些链接找到答案。

    接下来是蓝牙扫描功能的代码。  

    1.新建一个java class,定义蓝牙对象

public class BlueTooth_item_Bean {
    String blueToothDevice_Name; //蓝牙设备的名字
    String blueToothDevice_Adress; //蓝牙设备的mac地址
    String blueToothDevice_ConectStatus; //连接状态

    //判断内容是否相等
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof BlueTooth_item_Bean){
            if(blueToothDevice_Adress.equals(((BlueTooth_item_Bean) obj).blueToothDevice_Adress)
                    /*&& blueToothDevice_Name.equals(((BlueTooth_item_Bean) obj).blueToothDevice_Name)*/
            ){
                return true;
            }
        }else{
            return false;
        }
        return super.equals(obj);
    }


    @Override
    public int hashCode() {
        return blueToothDevice_Adress.hashCode();
    }

    public String getBlueToothDevice_Name() {
        return blueToothDevice_Name;
    }

    public void setBlueToothDevice_Name(String blueToothDevice_Name) {
        this.blueToothDevice_Name = blueToothDevice_Name;
    }

    public String getBlueToothDevice_Adress() {
        return blueToothDevice_Adress;
    }

    public void setBlueToothDevice_Adress(String blueToothDevice_Adress) {
        this.blueToothDevice_Adress = blueToothDevice_Adress;
    }

    public String getBlueToothDevice_ConectStatus() {
        return blueToothDevice_ConectStatus;
    }

    public void setBlueToothDevice_ConectStatus(String blueToothDevice_ConectStatus) {
        this.blueToothDevice_ConectStatus = blueToothDevice_ConectStatus;
    }
}

    2.新建java class,定义显示文本

public class ListViewAdapter extends BaseAdapter {
    private Context mcontext;                                    //上下文
    private List<BlueTooth_item_Bean> listDatas;              //listview需要用到的信息包括蓝牙名字和蓝牙设备的mac地址;
    private LayoutInflater layoutInflater;

    ListViewAdapter(Context mcontext, List<BlueTooth_item_Bean> listDatas){
        this.mcontext = mcontext;
        this.listDatas = listDatas;
        layoutInflater =  LayoutInflater.from(mcontext);
    }
    @Override
    public int getCount() {
        return listDatas.size();
    }

    @Override
    public Object getItem(int position) {
        return listDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        ListviewHolder listviewHolder;
        if(view ==null){
            listviewHolder = new ListviewHolder();
            view = layoutInflater.inflate(R.layout.layout_listview_item,null);
            listviewHolder.device_Name = (TextView) view.findViewById(R.id.device_name);
            listviewHolder.device_Address= (TextView) view.findViewById(R.id.device_address);
            listviewHolder.device_ConectStatus = (TextView) view.findViewById(R.id.device_status);
            view.setTag(listviewHolder);
        }else{
            listviewHolder =  (ListviewHolder) view.getTag();
        }
        listviewHolder.device_Name.setText(listDatas.get(position).blueToothDevice_Name);
        listviewHolder.device_Address.setText(listDatas.get(position).blueToothDevice_Adress);
        listviewHolder.device_ConectStatus.setText(listDatas.get(position).blueToothDevice_ConectStatus);
        return view;
    }



    static class  ListviewHolder{
        private TextView device_Name;
        private TextView device_Address;
        private TextView device_ConectStatus;
    }
}

    3.在activity里定义全局变量

    private static final int REQUEST_CODE_LOCATION_SETTINGS = 2; //用于Gps打开

    private BluetoothManager bluetoothManager;        //蓝牙管理器
    private BluetoothAdapter bluetoothAdapter;       //蓝牙适配器
    private static final int REQUEST_ENABLE_BLE = 1;    //蓝牙请求
    private static final long SCALE_PERIOD= 10*1000;     //扫描时长   10秒

    private static final String READ_SERVICE_UUID = "0000ffe0-0000-1000-8000-00805f9b34fb";
    private static final String READ_CHARACTERISTICS_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb"; //读的这个特征值的uuid

    //布局中的控件
    private Button startScaleButton; //开始扫描按钮
    private Button stopScaleButton; //停止扫描按钮
    private Button startReadButton; //开始读数据
    private Button stopReadButtion; //停止读数据
    private ListView listview;                             //展示扫描到的结果Listview;
    private List<BlueTooth_item_Bean> BlueToothDevice_Info;          //蓝牙设备的信息
    private ListViewAdapter adapter; //这个是定义的ListView的内部Listview_item的
    private ProgressBar progressbar;
    private Handler handler;
    private TextView noiseTextView;
    private TextView attentionTextView;
    private TextView meditationTextView;

    private static final int REQUEST_CODE_ACCESS_COARSE_LOCATION = 1;   //动态申请权限
    private BluetoothGatt mGatt;//通讯协议

    RunThread t1 = new RunThread(); //读写线程
    private BottomNavigationView bottomNavigation;
    private BlueTooth_item_Bean blueTooth_item_bean;

    4.onCreate函数

 @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bluetooth); //设置连接界面
        initView();                                                  //初始化控件
        initEvent();                                                //初始化事件
        initData();                                                  //初始化数据
        adapter = new ListViewAdapter(Ble1Activity.this,BlueToothDevice_Info);       //listView的适配器
        listview.setAdapter(adapter); //将获取到的数据放入展示列表

        checkPermission(); //判断SD卡是否存在

        //检测当前设备是否支持蓝牙ble
        if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
            Toast.makeText(Ble1Activity.this, "当前蓝牙不支持蓝牙设备", Toast.LENGTH_SHORT).show();
            finish();
        }

        //通过蓝牙管理器得到一个蓝牙适配器
        bluetoothManager  = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        if(bluetoothAdapter==null){
            Toast.makeText(Ble1Activity.this,"该设备不支持蓝牙",Toast.LENGTH_SHORT).show();
        }

        //android6.0之后要求有定位权限才可以扫描到蓝牙
        //动态申请权限
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){   //如果api版本大于23Android6.0的时候
            //判断是否具有权限
            if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
                //判断是否需要向用户解释为什么需要申请权限
                if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_COARSE_LOCATION)){
                    Toast.makeText(Ble1Activity.this,"需要获取定位才可以使用BLE扫描",Toast.LENGTH_SHORT).show();
                }
                //请求权限
                ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},REQUEST_CODE_ACCESS_COARSE_LOCATION);//请求码
            }
        }

        clickListView();
    }

    5.各类界面的初始化

//控件初始化
    private void initData() {
        //用于定时取消扫描
        handler = new Handler();
        //模拟蓝牙设备的信息
        BlueToothDevice_Info = new ArrayList<>();
       /* for(int i  = 0  ;i<3;i++){
            BlueTooth_item_Bean bluetooth_device_item_info = new BlueTooth_item_Bean();
            bluetooth_device_item_info.blueToothDevice_Name = "蓝牙设备名字"+i;
            bluetooth_device_item_info.blueToothDevice_Adress = "蓝牙设备mac地址"+i;
            bluetooth_device_item_info.blueToothDevice_ConectStatus = "蓝牙设备状态"+i;
            BlueToothDevice_Info.add(bluetooth_device_item_info);
        }*/
    }

    private void initView() {
        startScaleButton = (Button)findViewById(R.id.startScale);               //初始化控件。开始扫描按钮
        stopScaleButton= (Button)findViewById(R.id.stopScale);                  //初始化控件,停止扫描按钮
        startReadButton = findViewById(R.id.startRead);                         //初始化控件,开始读数据
        stopReadButtion = findViewById(R.id.stopRead);                          //初始化控件,停止读数据
        listview = (ListView) findViewById(R.id.listview);                    //用于展示扫描到的设备信息,Listview
        progressbar = (ProgressBar) findViewById(R.id.progressbar);
        progressbar.setVisibility(View.GONE);
    }



    private void initEvent() {
        startScaleButton.setOnClickListener(this);                    //开始扫描事件
        stopScaleButton.setOnClickListener(this);                    //停止扫描
        startReadButton.setOnClickListener(this); //开始读数据
        stopReadButtion.setOnClickListener(this); //停止读数据
    }

    6.各类click事件的初始化

//蓝牙点击事件
private void clickListView() {
        //请求到蓝牙后,点击搜索到的蓝牙进行连接
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                blueTooth_item_bean = BlueToothDevice_Info.get(i); //获取当前click事件的蓝牙对象
                if(blueTooth_item_bean.getBlueToothDevice_Adress()==null){
                    Toast.makeText(Ble1Activity.this,"请扫描蓝牙",Toast.LENGTH_SHORT).show();
                    return;
                }
                BluetoothDevice device = bluetoothAdapter.getRemoteDevice(blueTooth_item_bean.getBlueToothDevice_Adress()); //根据蓝牙地址获取设备信息
                if(device != null && blueTooth_item_bean.getBlueToothDevice_ConectStatus() != "连接成功") { //判空校验
                    mGatt = device.connectGatt(Ble1Activity.this, true, mBluetoothGattCallback); //进行连接
                    //连接后改写状态
                    blueTooth_item_bean.blueToothDevice_ConectStatus = "连接中...";
                    for (int j = 0; j < BlueToothDevice_Info.size(); j++) {
                        if(BlueToothDevice_Info.get(j).getBlueToothDevice_Adress().equals(blueTooth_item_bean.getBlueToothDevice_Adress())){ //移除蓝牙设备重新添加
                            BlueToothDevice_Info.remove(j);
                            break;
                        }
                    }
                    BlueToothDevice_Info.add(blueTooth_item_bean);
                    adapter.notifyDataSetChanged();
                }else{ //断开蓝牙连接
                    mGatt.disconnect();
                    mGatt.close();
                    //修改状态
                    blueTooth_item_bean = BlueToothDevice_Info.get(i); //获取当前click事件的蓝牙对象
                    //连接后改写状态
                    blueTooth_item_bean.blueToothDevice_ConectStatus = "尚未匹配";
                    for (int j = 0; j < BlueToothDevice_Info.size(); j++) {
                        if(BlueToothDevice_Info.get(j).getBlueToothDevice_Adress().equals(blueTooth_item_bean.getBlueToothDevice_Adress())){ //移除蓝牙设备重新添加
                            BlueToothDevice_Info.remove(j);
                            break;
                        }
                    }
                    BlueToothDevice_Info.add(blueTooth_item_bean);
                    adapter.notifyDataSetChanged();
                }
            }
        });
    }
 

//界面按钮点击事件
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.startScale:                                             //扫描操作     (扫描一定的事件就自动关闭扫描)

                //每次扫描之前都断开已经有的蓝牙连接
                if(mGatt != null){
                    mGatt.disconnect();
                    mGatt.close();
                }
                BlueToothDevice_Info.clear();
                progressbar.setVisibility(View.VISIBLE);
                bluetoothAdapter.startLeScan(mLescaleCallback); //安卓5.0以上后用新的扫描API
               /* bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
                    //LogUtil.e("系统版本:","<7.0");
                    bluetoothManager.getAdapter()
                            .startLeScan(mLescaleCallback);
                } else {//安卓7.0及以上的方案
                    //LogUtil.e("系统版本:",">=7.0");
                    mBluetoothLeScanner = bluetoothManager.getAdapter().getBluetoothLeScanner();
                    mBluetoothLeScanner.startScan(scanCallback);
                }*/
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        bluetoothAdapter.stopLeScan(mLescaleCallback);
                        progressbar.setVisibility(View.GONE);
                    }
                },SCALE_PERIOD);
                break;
            case R.id.stopScale:                                                  //停止扫描
                progressbar.setVisibility(View.GONE);
                bluetoothAdapter.stopLeScan(mLescaleCallback);
                break;
            case R.id.startRead:
                checkStartRead = true;
                //校验是否有设备连接
                if(blueTooth_item_bean != null && blueTooth_item_bean.blueToothDevice_ConectStatus != null && blueTooth_item_bean.getBlueToothDevice_ConectStatus().equals("连接成功")){
                    //Toast.makeText(Ble1Activity.this,"已经连接到蓝牙",Toast.LENGTH_SHORT).show();
                    //return;
                }else{
                    Toast.makeText(Ble1Activity.this,"尚未连接蓝牙",Toast.LENGTH_SHORT).show();
                    return;
                }
                BluetoothGattCharacteristic characteristic= mGatt.getService(UUID.fromString(READ_SERVICE_UUID))
                .getCharacteristic(UUID.fromString(READ_CHARACTERISTICS_UUID));
                mGatt.readCharacteristic(characteristic);
                break;
            case R.id.stopRead:
                checkStartRead = false;
                //校验是否有设备连接
                if(blueTooth_item_bean != null && blueTooth_item_bean.blueToothDevice_ConectStatus != null && blueTooth_item_bean.getBlueToothDevice_ConectStatus().equals("连接成功")){
                    //Toast.makeText(Ble1Activity.this,"已经连接到蓝牙",Toast.LENGTH_SHORT).show();
                    //return;
                }else{
                    Toast.makeText(Ble1Activity.this,"尚未连接蓝牙",Toast.LENGTH_SHORT).show();
                    return;
                }
                break;
        }

    }

    7.权限处理

//请求权限之后的请求处理
    // //执行完上面的请求权限后,系统会弹出提示框让用户选择是否允许改权限。选择的结果可以在回到接口中得知:
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if(requestCode==REQUEST_CODE_ACCESS_COARSE_LOCATION){
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //用户允许改权限,0表示允许,-1表示拒绝 PERMISSION_GRANTED = 0, PERMISSION_DENIED = -1
                //permission was granted, yay! Do the contacts-related task you need to do.
                //这里进行授权被允许的处理
            } else {
                //permission denied, boo! Disable the functionality that depends on this permission.
                //这里进行权限被拒绝的处理
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    //检测定位是否打开
    public static final boolean isLocationEnable(Context context) {
        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        boolean networkProvider = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        boolean gpsProvider = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        if (networkProvider || gpsProvider) return true;
        return false;
    }

    //如果没有打开,进入定位设置界面,让用户自己选择是否打开定位。选择的结果获取:
    private void setLocationService() {
        Intent locationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        this.startActivityForResult(locationIntent, REQUEST_CODE_LOCATION_SETTINGS);
    }

    @Override
    protected void onResume() {
        super.onResume();
        //确保蓝牙可以使用,如果不可以使用一个弹窗
        if(!bluetoothAdapter.enable()){
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent,REQUEST_ENABLE_BLE);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        //不同打开蓝牙
        if(requestCode ==REQUEST_ENABLE_BLE && resultCode == RESULT_CANCELED){
            finish();
            return;
        }
        //定位
        if (requestCode == REQUEST_CODE_LOCATION_SETTINGS) {
            if (isLocationEnable(this)) {
                //定位已打开的处理
            } else {
                //定位依然没有打开的处理
                Toast.makeText(Ble1Activity.this,"请打开GPS",Toast.LENGTH_SHORT).show();
            }
        } else super.onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }

    8.扫描的回调函数

//打开蓝牙后扫描的回调函数
    //扫描到设备之后的回调方法 安卓5.0以下
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) //这是一个因为版本号过高所以得进行控制的
    private BluetoothAdapter.LeScanCallback  mLescaleCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            if(device.getName()!=null && device.getAddress()!=null) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        final BlueTooth_item_Bean bean = new BlueTooth_item_Bean();
                        bean.blueToothDevice_Name = device.getName();
                        bean.blueToothDevice_Adress = device.getAddress();
                        int bondState = device.getBondState(); //对蓝牙状态进行判断
                        switch (bondState){
                            case BluetoothDevice.BOND_NONE:
                                bean.blueToothDevice_ConectStatus = "尚未匹配";
                                break;
                            case BluetoothDevice.BOND_BONDING:
                                bean.blueToothDevice_ConectStatus = "匹配中";
                                break;
                            case BluetoothDevice.BOND_BONDED:
                                bean.blueToothDevice_ConectStatus = "匹配成功";
                        }
                        if(BlueToothDevice_Info.contains(bean)) {
                            //如果集合中已经包含相同的对象,则不添加进去
                        }else{
                            BlueToothDevice_Info.add(bean);
                            adapter.notifyDataSetChanged();
                        }
                    }
                });
            }
        }
    };

    9.蓝牙连接的回调函数

//连接的回调函数
    /**
     * @description 连接后的回调函数
     * @param
     * @return
     * @author momo
     * @time 2021/3/4
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) //这是一个因为版本号过高所以得进行控制的
            BluetoothGattCallback mBluetoothGattCallback=new BluetoothGattCallback() {        //连接回调
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                //System.out.println("连接成功");
                gatt.discoverServices();  //跳转到发现蓝牙服务
            }else if (newState == BluetoothProfile.STATE_DISCONNECTED) {   //断开连接
                //System.out.println("断开连接");
                //连接后改写状态
                blueTooth_item_bean.blueToothDevice_ConectStatus = "尚未连接";
                for (int j = 0; j < BlueToothDevice_Info.size(); j++) {
                    if(BlueToothDevice_Info.get(j).getBlueToothDevice_Adress().equals(blueTooth_item_bean.getBlueToothDevice_Adress())){ //移除蓝牙设备重新添加
                        BlueToothDevice_Info.remove(j);
                        break;
                    }
                }
                BlueToothDevice_Info.add(blueTooth_item_bean);
                /*adapter.notifyDataSetChanged();*/
                //只有在线程中才可以进行修改
                Ble1Activity.this.runOnUiThread(new Runnable() {
                    public void run() {
                        adapter.notifyDataSetChanged();
                    }
                });
                mGatt.close();
            }
        }

    10.发现服务

/**
         * @description 发现服务
         * @param
         * @return
         * @author momo
         * @time 2021/3/4
         */
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            //System.out.println("onServicesDiscovered: ======发现服务");
            List<BluetoothGattService> services = gatt.getServices();
            //System.out.println("onServicesDiscovered有几个服务:"+services.size());

            //连接后改写状态
            blueTooth_item_bean.blueToothDevice_ConectStatus = "连接成功";
            for (int j = 0; j < BlueToothDevice_Info.size(); j++) {
                if(BlueToothDevice_Info.get(j).getBlueToothDevice_Adress().equals(blueTooth_item_bean.getBlueToothDevice_Adress())){ //移除蓝牙设备重新添加
                    BlueToothDevice_Info.remove(j);
                    break;
                }
            }
            BlueToothDevice_Info.add(blueTooth_item_bean);
            /*adapter.notifyDataSetChanged();*/
            //只有在线程中才可以进行修改
            Ble1Activity.this.runOnUiThread(new Runnable() {
                public void run() {
                    adapter.notifyDataSetChanged();
                }
            });
        }

    11.读写数据

  /**
         * @description 读数据
         * @param
         * @return
         * @author momo
         * @time 2021/3/4
         */
        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            for (int i = 0; i < characteristic.getValue().length; i++) {
                System.out.println("onCharacteristicRead:读出的值为 "+characteristic.getValue()[i]); //读出的应该是特征数量的数据
            }
            //直接有UUID写
            System.out.println("写入...");
            BluetoothGattCharacteristic characteristic = mGatt.getService(UUID.fromString(READ_SERVICE_UUID))
.getCharacteristic(UUID.fromString(READ_CHARACTERISTICS_UUID));
            characteristic.setValue("AAAA123456789FFFF");
            mGatt.writeCharacteristic(characteristic);


        }

        /**
         * @description 写数据
         * @param
         * @return
         * @author momo
         * @time 2021/3/4
         */
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            if (status==BluetoothGatt.GATT_SUCCESS){
                System.out.println("onCharacteristicWrite: 写入成功");
                //gatt.readCharacteristic(characteristic);
                //onServicesDiscovered(gatt,status);
            }else {
                System.out.println("onCharacteristicWrite: 失败");
            }
        }
    };

 

结尾

    时间比较仓促只来得及简单贴上代码。有一些细小的bug等我有时间再慢慢调整。

    关于读写那边是有些许问题的,相关的信息可以点击参考文档进行修改。

    感谢大家阅读。

 

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
以下是使用C#实现低功耗蓝牙BLE数据读写功能的示例代码: ```C# using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.Devices.Bluetooth; using Windows.Devices.Bluetooth.GenericAttributeProfile; using Windows.Devices.Enumeration; namespace BleCommunication { class Program { static void Main(string[] args) { var task = MainAsync(args); task.Wait(); } static async Task MainAsync(string[] args) { // 查询所有蓝牙设备 string selector = BluetoothLEDevice.GetDeviceSelector(); var devices = await DeviceInformation.FindAllAsync(selector); // 过滤出指定名称的设备 var device = devices.FirstOrDefault(d => d.Name == "My BLE Device"); if (device != null) { // 连接设备 var bleDevice = await BluetoothLEDevice.FromIdAsync(device.Id); // 查询服务 var serviceUuid = Guid.Parse("0000fff0-0000-1000-8000-00805f9b34fb"); var serviceResult = await bleDevice.GetGattServicesForUuidAsync(serviceUuid); var service = serviceResult.Services.FirstOrDefault(); if (service != null) { // 查询特征值 var characteristicUuid = Guid.Parse("0000fff1-0000-1000-8000-00805f9b34fb"); var characteristicResult = await service.GetCharacteristicsForUuidAsync(characteristicUuid); var characteristic = characteristicResult.Characteristics.FirstOrDefault(); if (characteristic != null) { // 订阅特征值通知 var status = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); if (status == GattCommunicationStatus.Success) { characteristic.ValueChanged += (sender, args) => { // 处理接收到的数据 var data = args.CharacteristicValue.ToArray(); Console.WriteLine("Received data: {0}", BitConverter.ToString(data)); }; // 发送数据 var dataToSend = new byte[] { 0x01, 0x02, 0x03 }; var writeStatus = await characteristic.WriteValueAsync(dataToSend.AsBuffer()); if (writeStatus == GattCommunicationStatus.Success) { Console.WriteLine("Data sent successfully."); } else { Console.WriteLine("Failed to send data."); } } else { Console.WriteLine("Failed to subscribe to notifications."); } } else { Console.WriteLine("Characteristic not found."); } } else { Console.WriteLine("Service not found."); } } else { Console.WriteLine("Device not found."); } Console.ReadLine(); } } } ``` 请注意,此示例仅用于演示BLE通信的基本过程。在实际应用中,您需要根据设备的具体规格和特性来编写更复杂的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值