接上一篇
进行设备连接
引用官方的文档
要在两台设备上的应用之间创建连接,必须同时实现服务器端和客户端机制,因为其中一台设备必须开放服务器套接字,而另一台设备必须发起连接(使用服务器设备的 MAC 地址发起连接)。 当服务器和客户端在同一 RFCOMM 通道上分别拥有已连接的
BluetoothSocket
时,二者将被视为彼此连接。
由上面的引用可知,要想创建两个应用之间的连接,必须同时实现服务器端和客户端机制,下面,分别介绍怎样实现为服务器端和客户端机制。
实现为服务器
当您需要连接两台设备时,其中一台设备必须通过保持开放的
BluetoothServerSocket
来充当服务器。 服务器套接字的用途是侦听传入的连接请求,并在接受一个请求后提供已连接的BluetoothSocket
。 从BluetoothServerSocket
获取BluetoothSocket
后,可以(并且应该)舍弃BluetoothServerSocket
,除非您需要接受更多连接。
下面是作为服务端的代码
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { BluetoothServerSocket tmp = null; try { tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { } mmServerSocket = tmp; mState = STATE_LISTEN; } public void run() { setName("AcceptThread"); BluetoothSocket socket = null; while (mState != STATE_CONNECTED) { try { socket = mmServerSocket.accept(); } catch (IOException e) { break; } if (socket != null) { synchronized (BluetoothService.this) { switch (mState) { case STATE_LISTEN: case STATE_CONNECTING: connected(socket, socket.getRemoteDevice()); break; case STATE_NONE: case STATE_CONNECTED: try { socket.close(); } catch (IOException e) { } break; } } } } } public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } }
这里解释一下,为什么要新开一个线程来作为服务端,因为通过调用 accept()
这是一个阻塞调用。
注意:mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);中的MY_UUID必须与客服端连接时的UUID一致。
总结一下作为服务端的步骤:
- 通过调用
listenUsingRfcommWithServiceRecord(String, UUID)
获取BluetoothServerSocket
。 - 通过调用
accept()
开始侦听连接请求。 - 如果不想让更多的设备连接,则在连接后调用
close()
关闭。
实现为客户端
先看下作为客户端的代码
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; try { tmp = device.createRfcommSocketToServiceRecord( MY_UUID); } catch (IOException e) { } mmSocket = tmp; mState = STATE_CONNECTING; } public void run() { setName("ConnectThread"); mAdapter.cancelDiscovery(); try { mmSocket.connect(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException e2) { } return; } synchronized (BluetoothService.this) { mConnectThread = null; } connected(mmSocket, mmDevice); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
这里有一点需要注意,也是官方文档中强调的
**注:**在调用
connect()
时,应始终确保设备未在执行设备发现。 如果正在进行发现操作,则会大幅降低连接尝试的速度,并增加连接失败的可能性。
因此,在进行连接之前必须调用mAdapter.cancelDiscovery();
来关闭查找设备。这里总结一下作为客户端的步骤:
- 使用
BluetoothDevice
,通过调用createRfcommSocketToServiceRecord(UUID)
获取BluetoothSocket
。(这里的UUID必须与服务端的保持一致) - 通过调用
connect()
发起连接。
如果两台设备之前尚未配对,则在连接过程中,Android 框架会自动向用户显示配对请求通知或对话框,如下图所示。
进行配对之后就可以进行通信及数据的传输了。
数据传输
通过上面的几步,这时已经可以实现设备之间的连接了。下面说一下设备之间的通信。
其实在两台设备连接成功后,每台设备都会有一个已连接的 BluetoothSocket
。我们则可以利用 BluetoothSocket
,来进行数据的传输。看代码
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // 获取BluetoothSocket的input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; mState = STATE_CONNECTED; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; while (mState == STATE_CONNECTED) { try { bytes = mmInStream.read(buffer); Log.d(TAG, "已经连接"); mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "disconnected", e); break; } } } //写数据 public void write(byte[] buffer) { try { mmOutStream.write(buffer); //发送消息到主线程 mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } }
从上面代码中可以看到,首先是通过BluetoothSocket来拿到InputStream和OutputStream,然后利用read
,write
方法来读取和写入数据。
结束语
本文的内容是基于普通蓝牙进行描述的,主要讲解了怎样操作蓝牙及进行设备间的通讯。不过现在好多都是在BLE蓝牙设备间进行通讯了,当然,我也会针对BLE蓝牙设备在写一篇文章,本文就是为后面的BLE蓝牙讲解做准备的。
文中都是截取的主要代码,要获取全部源码请点击这里。