Android蓝牙开发
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
前言
这是我大二做的一个智能小车配套使用的APP用Android的蓝牙接口实现当时有些os相关的内容Thread
之类还有一些Android接口、java语法我其实不是很理解。学了操作系统再来回顾一下并整理项目代码项目具有很高的复用性特别是蓝牙部分。
reference
项目参考了稚晖君的开源项目 https://github.com/peng-zhihui/BluetoothTouch
Android蓝牙开发官方文档 https://developer.android.google.cn/guide/topics/connectivity/bluetooth
设置蓝牙
这个在MainActivity
中设置分为两步
- 获取
BluetoothAdapter
这是所有蓝牙活动的基础
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Get local Bluetooth adapter
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
else
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
showToast("Bluetooth is not available", Toast.LENGTH_LONG);
finish();
return;
}
}
- 使能蓝牙首先确定蓝牙是否启用若未启用调用
startActivityForResult
传递ACTION_REQUEST_ENABLE
目标动作这些 大写变量 实际是Android定义好的字符串若以启用传入BluetoothHandler
和BluetoothAdapter
实例化我们自定义的蓝牙服务类BluetoothChatService
后面慢慢介绍实际就是蓝牙接口封装起来的一个类
public void onStart()
{
super.onStart();
// If BT is not on, request that it be enabled.
// setupChat() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else
setupBTService(); // Otherwise, setup the chat session
}
private void setupBTService()
{
if (mChatService != null)
return;
if (mBluetoothHandler == null)
mBluetoothHandler = new BluetoothHandler(this);
mChatService = new BluetoothChatService(mBluetoothHandler, mBluetoothAdapter); // Initialize the BluetoothChatService to perform Bluetooth connections
}
连接设备
通过retry
判断是否断线重连否则创建新连接像http
协议有 ipv4 和 ipv6 地址以太网协议有 MAC 地址蓝牙也有地址在蓝牙构建的网络中标识设备或者蓝牙对象。
private void connectDevice(Intent data, boolean retry)
{
if (retry) {
if (btDevice != null && !stopRetrying) {
mChatService.start(); // This will stop all the running threads
mChatService.connect(btDevice, btSecure); // Attempt to connect to the device
}
} else { // It's a new connection
stopRetrying = false;
mChatService.newConnection = true;
mChatService.start(); // This will stop all the running threads
if (data.getExtras() == null)
return;
// 获取设备蓝牙地址并连接设备
String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS); // Get the device Bluetooth address
btSecure = data.getExtras().getBoolean(DeviceListActivity.EXTRA_NEW_DEVICE); // If it's a new device we will pair with the device
btDevice = mBluetoothAdapter.getRemoteDevice(address); // Get the BluetoothDevice object
mChatService.nRetries = 0; // Reset retry counter
mChatService.connect(btDevice, btSecure); // Attempt to connect to the device
showToast(getString(R.string.connecting), Toast.LENGTH_SHORT);
}
}
BluetoothChatService.connect
connect
方法的定义如下这里有mConnectThread
和mConnectedThread
两个用于连接和保持连接的线程先cancel
之前的线程再重新连接start
public synchronized void connect(BluetoothDevice device, boolean secure)
{
stopReading = true;
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device, secure);
mConnectThread.start();
setState(STATE_CONNECTING);
}
BluetoothChatService.ConnectThread
这里final
关键字修饰变量在初始化后不可更改。这里BluetoothSocket
是用于收发数据的工具在网络通信的编程开发中很常见。这里仅实现了作为客户端进行连接坑补充作为服务端等待连接的线程实现。基本连接流程如下
- 使用
BluetoothDevice
调用createRfcommSocketToServiceRecord(UUID)
获取蓝牙套接字BluetoothSocket
这个UUID
是由服务端和客户端共同协商的RFCOMM就是蓝牙通信所使用的的信道 - 阻塞调用
socket
的connect()
方法系统执行SDP查找具有指定UUID
的设备若查找成功并且对方设备接受连接开始蓝牙通信共享RFCOMM信道若超时则抛出一个IOException
- 蓝牙连接完毕之后调用
BluetoothChatService.connected
启动保持连接线程或者说通信线程BluetoothChatService.ConnectedThread
.
private class ConnectThread extends Thread
{
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device, boolean secure)
{
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
if (secure)
tmp = mmDevice.createRfcommSocketToServiceRecord(UUID_RFCOMM_GENERIC);
else
tmp = mmDevice.createInsecureRfcommSocketToServiceRecord(UUID_RFCOMM_GENERIC);
} catch (IOException e) {
if (D)
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
}
public void run()
{
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
newConnection = false;
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
if (D)
Log.e(TAG, "unable to close() " + mSocketType
+ " socket during connection failure", e2);
}
if (!newConnection)
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel()
{
try {
mmSocket.close();
} catch (IOException e) {
if (D)
Log.e(TAG, "close() of connect " + mSocketType
+ " socket failed", e);
}
}
}
传递数据
BluetoothChatService.ConnectedThread
成功连接蓝牙设备后双方均有一个BluetoothSocket
这时可以分享信息数据传递流程如下
- 通过
BluetoothSocket
获取I/O对象InputStream
和OutputStream
; - 通过
read(byte[])
和write(byte[])
进行以字节为单位数据读写实际上读要不断进行因此在线程的run()
方法中实现这里读到后直接解析了更好地做法应该定义一个parser
类负责数据的解析坑。
private class ConnectedThread extends Thread
{
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType)
{
if (D)
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
if (D)
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
stopReading = false;
}
public void run()
{
if (D)
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (!stopReading) {
try {
if (mmInStream.available() > 0) { // Check if new data is available
bytes = mmInStream.read(buffer); // Read from the InputStream
/*************** 解释器 **************/
String readMessage = new String(buffer, 0, bytes);
String[] splitMessage = readMessage.split(",");
if (D) {
Log.i(TAG, "Received string: " + readMessage);
for (int i = 0; i < splitMessage.length; i++)
Log.i(TAG, "splitMessage[" + i + "]: " + splitMessage[i]);
}
// 命令解析...
}
} catch (IOException e) {
if (D)
Log.e(TAG, "disconnected", e);
if (!stopReading) {
cancel();
connectionLost();
}
return;
}
}
}
/**
* Write to the connected OutStream.
*
* @param buffer The bytes to write
*/
public void write(byte[] buffer)
{
try {
mmOutStream.write(buffer);
} catch (IOException e) {
if (D)
Log.e(TAG, "Exception during write", e);
}
}
public void cancel()
{
stopReading = true;
if (mmInStream != null) {
try {
mmInStream.close();
} catch (Exception ignored) {
}
}
if (mmOutStream != null) {
try {
mmOutStream.close();
} catch (Exception ignored) {
}
}
if (mmSocket != null) {
try {
mmSocket.close();
} catch (Exception ignored) {
}
}
}
}