本app只能在android的日志查看蓝牙发送的数据,可自己改进。但是在使用前,确保你所连接的蓝牙已配对
在AndroidManifest.xml我们还需导入以下权限:
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 在Android 10以上还需要 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 唤醒锁权限,防止后台被杀。 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 读取蓝牙UUID权限。 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 蓝牙连接权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 蓝牙检测权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
在MainActivity引用以下包:
import static java.lang.Thread.sleep;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;
在MainActivity定义如下参数:
public static BluetoothAdapter mBluetoothAdapter; // 蓝牙实例
private static final int REQUEST_BLUETOOTH_CONNECT = 1; // 蓝牙权限码
public static InputStream inputStream; // 蓝牙通信输入流
public static OutputStream outputStream; // 蓝牙通信输出流
public static boolean Bluetooth_flag = false; // 当前蓝牙连接状态
public static BluetoothSocket socket = null; // 蓝牙socket连接实例
public static Thread Blue_Thread=null,connect_thread; // 蓝牙获取信息线程 蓝牙连接线程
对于android14来说需要去检测权限是否开启以及初始化:
// 用于告诉Android的Lint工具忽略缺少权限声明的警告
@SuppressLint("MissingPermission")
public void Initpermission() { // 初始化蓝牙权限
// 获取系统默认的蓝牙适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 记录当前的状态
Log.d( "Blue_tooth", "蓝牙正在连接0" );
// 创建一个意图(Intent),用于请求用户开启蓝牙
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
// 使用startActivityForResult方法启动一个新的活动(Activity),并请求用户开启蓝牙。这里的100是一个请求码,用于在请求完成后识别结果
startActivityForResult(enableBtIntent, 100);
// 用于连接到蓝牙设备
connectToBluetoothDevice();
}
连接蓝牙的代码:
@SuppressLint("MissingPermission") // 忽略缺少权限的警告
private static void connectToBluetoothDevice() {
// 创建一个新的线程来处理蓝牙连接
connect_thread = new Thread(() -> {
Log.d("Blue_tooth", "蓝牙正在连接"); // 记录日志,表示蓝牙连接正在进行
// 检查socket是否已经存在
if (socket != null) {
// 如果socket已经存在,但未连接,且Blue_Thread线程存在
if (!socket.isConnected() && Blue_Thread != null) {
Blue_Thread.stop(); // 停止Blue_Thread线程
Bluetooth_flag = true; // 设置标志位,表示蓝牙连接尝试正在进行
}
} else {
// 如果socket不存在,设置HC05蓝牙模块的MAC地址
String hc05MacAddress = "98:D3:61:F7:0F:46"; // 替换为HC05的MAC地址
// 通过MAC地址获取蓝牙设备对象
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(hc05MacAddress);
try {
// 创建RFCOMM(串行端口)类型的socket并连接
socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"));
socket.connect(); // 连接socket
inputStream = socket.getInputStream(); // 获取输入流
outputStream = socket.getOutputStream(); // 获取输出流
// 调用Bule_hread()方法,可能是一个拼写错误,应该是Blue_thread
Bule_hread();
Blue_Thread.start(); // 启动Blue_Thread线程
} catch (IOException e) {
e.printStackTrace(); // 打印异常信息
}
}
});
connect_thread.start(); // 启动连接线程
}
蓝牙连接成功后需要发送数据以及接收数据:
发送数据部分:
public static void Blue_send(byte[] b) {
// 检查socket是否已经存在
if (socket != null) {
// 如果socket已经存在,检查是否已经连接
if (socket.isConnected()) {
try {
// 如果socket已经连接,通过输出流发送数据
outputStream.write(b);
} catch (IOException e) {
// 如果在写入数据时发生IOException,设置Bluetooth_flag为false
Bluetooth_flag = false;
// 抛出一个RuntimeException,包含原始的IOException
throw new RuntimeException(e);
}
} else {
// 如果socket存在但未连接,尝试重新连接蓝牙设备
connectToBluetoothDevice();
// 记录日志,表示蓝牙未连接
Log.d("Blue_tooth", "蓝牙未连接");
}
} else {
// 如果socket不存在,尝试连接蓝牙设备
connectToBluetoothDevice();
// 记录日志,表示蓝牙未连接
Log.d("Blue_tooth", "蓝牙未连接");
}
}
接收部分:
@SuppressLint("MissingPermission") // 忽略缺少权限的警告
public static void Bule_hread() {
// 创建一个新的线程来处理蓝牙数据接收
Blue_Thread = new Thread(() -> {
byte[] buffer = new byte[1024]; // 创建一个1024字节的缓冲区来读取数据
byte[] buffer1 = new byte[1024]; // 创建另一个1024字节的缓冲区来存储接收到的数据
int bytes; // 用于存储每次读取的字节数
int buffer1Index = 0; // 用于记录buffer1中的当前索引位置
while (true) { // 无限循环,持续读取数据
try {
bytes = inputStream.read(buffer); // 从输入流中读取数据到buffer
// 将读取到的数据追加到buffer1中
System.arraycopy(buffer, 0, buffer1, buffer1Index, bytes);
buffer1Index += bytes; // 更新buffer1中的索引位置
// 处理接收到的数据
if (buffer1Index >= 8) { // 如果接收到的数据达到8字节
String received = new String(buffer1, 0, 8); // 将前8字节数据转换为字符串
Log.d("Blue_tooth_data", received); // 记录日志,显示接收到的数据
buffer1Index = 0; // 重置buffer1的索引位置
Arrays.fill(buffer1, (byte) 0); // 清空buffer1
Arrays.fill(buffer, (byte) 0); // 清空buffer
}
try {
Thread.sleep(50); // 线程休眠50毫秒,减少CPU使用率
} catch (InterruptedException e) {
throw new RuntimeException(e); // 如果线程被中断,抛出RuntimeException
}
} catch (IOException e) {
connectToBluetoothDevice(); // 如果读取数据时发生IOException,尝试重新连接蓝牙设备
e.printStackTrace(); // 打印异常信息
}
}
});
Blue_Thread.start(); // 启动Blue_Thread线程
}
在app退出,防止泄露或者其他原因,最好在同时清理回收参数以及各种资源:
@Override
public void onDestroy() {
super.onDestroy();
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (Bluetooth_flag) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
至此,所有代码部分已经呈现,通信的波特率默认115200,在使用前查看自己蓝牙所用波特率,这份代码在连接蓝牙使用了一个线程,然后接收数据也用了一个线程,连接线程是为了防止在进入app界面,因为连接导致会出现白屏现象,虽然无所谓,但是不好看,接收线程是为了能一直接受,其实还能用其他方式写,比如Handle或者线程池,都能进行很好的优化。