当前位置: 首页 > 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.lryc.cn/news/609167.html

相关文章:

  • Kaggle 竞赛入门指南
  • ELECTRICAL靶机复现练习笔记
  • C++中多线程和互斥锁的基本使用
  • 【数据结构】二叉树的顺序结构实现
  • 15_01_opencv_形态学滤波
  • 35.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--数据缓存
  • Android 之 RxJava2
  • Kali基础知识点【1】
  • 基于图像识别与分类的中国蛇类识别系统
  • gitee使用教程
  • 电路原理图绘制专业实战教程2
  • 生成式人工智能展望报告-欧盟-04-社会影响与挑战
  • Java中手动床架一个线程池
  • [硬件电路-134]:模拟电路 - 运算放大器常见运算:两模拟信号相加、相减、单模拟信号的积分、微分...
  • template<typename R = void> 意义
  • 【Python练习】075. 编写一个函数,实现简单的语音识别功能
  • golang的包和闭包
  • slice() 和 splice()
  • 决策树模型知识点整理:从原理到实战(含可视化与调参)
  • Corrosion2靶机练习笔记
  • 【图像处理基石】如何使用deepseek进行图像质量的分析?
  • 【Django】-9- 单元测试和集成测试(上)
  • Day23--回溯--39. 组合总和,40. 组合总和 II,131. 分割回文串
  • 机器人抓取流程介绍与实现——机器人抓取系统基础系列(七)
  • 深度学习中卷积与互相关
  • [ java Thread 线程 ] 由“一对一“到“一对多“
  • 【Linux网络编程基础--socket地址API】
  • 使用 Vuepress + GitHub Pages 搭建项目文档
  • GraphRAG:基于知识图谱的检索增强生成技术解析
  • 微分方程模型:用“变化率”的语言,描绘世间万物的动态演化