当前位置: 首页 > news >正文

Android 之 蓝牙通信(2.0 经典)

 ​​一、环境配置​

1. ​​添加依赖​

在 build.gradle 中添加库依赖:

dependencies {implementation 'com.github.akexorcist:bluetoothspp:1.0.0'  
}
2. ​​权限声明(AndroidManifest.xml)​
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ 额外权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 6.0+ 需要 --> [4,8](@ref)

二、页面布局(activity_main.xml)

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><!-- 状态显示 --><TextViewandroid:id="@+id/tv_status"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="蓝牙未连接"android:textSize="18sp"/><!-- 设备列表 --><ListViewandroid:id="@+id/lv_devices"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"/><!-- 操作按钮 --><Buttonandroid:id="@+id/btn_scan"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="扫描设备"/><Buttonandroid:id="@+id/btn_send"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="发送数据"android:enabled="false"/> <!-- 默认禁用 --></LinearLayout>

 ​​三、核心代码(MainActivity.java)​

1. ​​初始化蓝牙服务​

public class MainActivity extends AppCompatActivity {private BluetoothSPP bt;private TextView tvStatus;private Button btnScan, btnSend;private ListView lvDevices;private List<BluetoothDevice> deviceList = new ArrayList<>();private ArrayAdapter<String> adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tvStatus = findViewById(R.id.tv_status);btnScan = findViewById(R.id.btn_scan);btnSend = findViewById(R.id.btn_send);lvDevices = findViewById(R.id.lv_devices);// 初始化设备列表适配器adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);lvDevices.setAdapter(adapter);// 初始化蓝牙bt = new BluetoothSPP(this);if (!bt.isBluetoothAvailable()) {Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_SHORT).show();finish();}// 设置数据接收监听器bt.setOnDataReceivedListener((data, message) -> {tvStatus.setText("收到数据: " + message); // [1,6](@ref)});// 设置连接状态监听器bt.setBluetoothConnectionListener(new BluetoothSPP.BluetoothConnectionListener() {@Overridepublic void onDeviceConnected(String name, String address) {tvStatus.setText("已连接至 " + name);btnSend.setEnabled(true); // 启用发送按钮}@Overridepublic void onDeviceDisconnected() {tvStatus.setText("连接断开");btnSend.setEnabled(false);}@Overridepublic void onDeviceConnectionFailed() {tvStatus.setText("连接失败");}});// 启动蓝牙服务bt.setupService();bt.startService(BluetoothState.DEVICE_OTHER); // [1,6](@ref)// 扫描按钮事件btnScan.setOnClickListener(v -> scanDevices());// 发送按钮事件btnSend.setOnClickListener(v -> sendData());// 设备列表点击事件lvDevices.setOnItemClickListener((parent, view, position, id) -> {BluetoothDevice device = deviceList.get(position);connectDevice(device.getAddress()); // 连接选中的设备 [3](@ref)});}// 扫描设备private void scanDevices() {if (!checkPermissions()) {requestPermissions(); // 动态申请权限return;}deviceList.clear();adapter.clear();bt.setDeviceTarget(BluetoothState.DEVICE_OTHER);bt.startDiscovery(); // 开始扫描 [6](@ref)// 注册广播接收器IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(discoveryReceiver, filter);}// 广播接收器(处理设备发现)private final BroadcastReceiver discoveryReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);deviceList.add(device);adapter.add(device.getName() + "\n" + device.getAddress()); // 显示设备名和地址 [8](@ref)}}};// 连接设备(带延迟避免冲突)private void connectDevice(String address) {new Handler().postDelayed(() -> {bt.connect(address); // 延迟500ms连接 [3](@ref)}, 500);}// 发送数据private void sendData() {bt.send("Hello Device!", true); // 发送字符串(自动添加CR/LF)[1](@ref)}// 权限检查(兼容Android 12+)private boolean checkPermissions() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {return checkSelfPermission(BLUETOOTH_SCAN) == PERMISSION_GRANTED && checkSelfPermission(BLUETOOTH_CONNECT) == PERMISSION_GRANTED;} else {return checkSelfPermission(ACCESS_FINE_LOCATION) == PERMISSION_GRANTED;}}// 动态请求权限private void requestPermissions() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {requestPermissions(new String[]{Manifest.permission.BLUETOOTH_SCAN,Manifest.permission.BLUETOOTH_CONNECT,Manifest.permission.ACCESS_FINE_LOCATION}, 1);} else {requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);}}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(discoveryReceiver); // 注销广播bt.stopService(); // 释放资源 [6](@ref)}
}

http://www.dtcms.com/a/313212.html

相关文章:

  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-58,(知识点:硬件产品的功率优化)
  • C++中多线程和互斥锁的基本使用
  • 【RH124 问答题】第 8 章 监控和管理 Linux 进程
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现实时食物水果的检测识别(C#代码UI界面版)
  • 使用 Spring Initializr 生成项目结构:Java 开发效率提升指南
  • 【QT】常⽤控件详解(二)windowOpacitycursorfontsetToolTipfocusPolicystyleSheet
  • 大语言模型涉及的一些概念(持续更新)
  • VisualStudio的一些开发经验
  • 思二勋:数字资产化与资产数权化是RWA运作的核心逻辑
  • AtCoder Beginner Contest 417
  • MySQL事务与存储引擎的学习(一)
  • Docker国内镜像列表
  • Effective C++ 条款19: 设计class犹如设计type
  • Python从入门到精通计划Day02: Python语法探秘:当现代艺术遇到古典音乐
  • 最小半径覆盖问题【C++解法+二分+扫描线】
  • 【CF】Day118——杂题 (随机哈希 / 思维 | 贪心 / DP | 位运算构造 | 状态压缩 + 建图 + 最短路 | 构造 | 贪心)
  • 使用纯Docker命令搭建多服务环境(Linux版)
  • Python篇---包
  • 在Ansys Mechanical中对磨损进行建模
  • 力扣经典算法篇-40-螺旋矩阵(方向遍历:方向数组+已访问元素集合)
  • 【ROS2】常用命令
  • 04.Redis 的多实例
  • 双八无碳小车设计【16张cad】三维图+设计说明书
  • 【C++ 初级工程师面试--5】inline内联函数特点 、和普通函数的区别、什么时候适合内联?
  • json-server 快速搭建本地 Mock 数据服务
  • Day23--回溯--39. 组合总和,40. 组合总和 II,131. 分割回文串
  • Android 之 MVC架构
  • 线段树学习笔记 - 摩尔投票问题
  • I2C基础
  • mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件