最近一直在做与bluetooth相关的应用。主要涉及Android手机蓝牙的多连接问题。网上几乎没有与蓝牙多连接相关的具体实现资料,所以我开始从android的官方文档入手,大半夜的一个人坐下面看那英文文档,真TMD不是滋味,现在回想下当年做的英语阅读理解真似一坨shit。不过功夫不负有心人,终于搞清楚了它的构架和通信模式。这里我先讲bluetooth的基本操作,然后再深入讲解它的多连接问题(大家期待的重头戏)。注意:我这里主要讲的是多连接的核心实现,至于蓝牙的一些基础操作,我只是简单的介绍。如果有不懂的可以参考其他资料。我也做了一个测试Demo,里面的代码基本参考的官方文档,若有疑问可以去官网上看看。我试过一次可以连接三个手机。当然这不一定是极限数据,因为设备有限。有条件的朋友可以修改下代码,做下压力测试。
Demo代码下载:http://download.csdn.net/detail/wangwang6233/7188881
官方文档:http://developer.android.com/guide/topics/connectivity/bluetooth.html
参考博客:http://zhouyunan2010.iteye.com/blog/1186021
流程:
(1)蓝牙的介绍,相关API使用说明,使用蓝牙的准备工作。
(2)蓝牙的开启和关闭。
(3)设置设备可被搜索。
(4)搜索设备及广播接收器的注册。
(5)蓝牙的配对。
(6)蓝牙的连接服务端和客户端
(7)蓝牙的多连接操作。
讲解:
(1)蓝牙的介绍,相关API使用说明,使用蓝牙的准备工作。
蓝牙,是一种支持设备短距离通信(一般10m内)的无线电技术。理论上一个蓝牙设备可以连接7个蓝牙设备(我没试过,只是理论上)。首先可行性是没问题的。其他蓝牙信息我就不阐述了,大家问度娘吧!在android app上使用bluetooth时需在AndroidManifest.xml中加上权限:
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permissionandroid:name="android.permission.BLUETOOTH" />
我简单说下相关的API类,和常用的方法。
BluetoothAdapter:顾名思义,蓝牙适配器,蓝牙的打开、关闭、搜索都和它有关BluetoothAdapter.getDefaultAdapter()获取。
BluetoothDevice:看名字就知道,这个类是描述一个蓝牙设备,从它可以获取蓝牙的地址和设备名getAddress(),getName()。并且蓝牙设备有三种状态BOND_BONDED、BOND_BONDING、BOND_NONE分别是已绑定,绑定中、未绑定。
BluetoothServerSocket:这是服务端,通过accept()返回BluetoothSocket。既然是Socket相信大家都再熟悉不过了吧!如果你不太清楚socket编程,那就先去看Java基础吧!这里我也不能偏题。
BluetoothSocket:这是客户端,connect()与服务端进行连接。通过它回去输入输出流。
(2)蓝牙的开启和关闭。
打开蓝牙:
- private void startBluetooth() {
- if (mBluetoothAdapter == null) {
-
- Log.d(TAG, "device is not supported bluebooth");
- return;
- }
- if (!mBluetoothAdapter.isEnabled()) {
- mBluetoothAdapter.enable();
- }
- }
关闭蓝牙:
- if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
- mBluetoothAdapter.disable();
- }
(3)
设置设备可被搜索。
-
- private void ensureDiscoverable() {
- if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- Intent discoverableIntent = new Intent(
- BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- discoverableIntent.putExtra(
- BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
- startActivity(discoverableIntent);
- }
- }
(4)
搜索设备及广播接收器的注册。
记得在onCreate()中注册,在onDestory()中unregisterReceiver(searchDevices);这是android广播机制的基础,不懂的可以回去看看android广播基础了。
- private void register2Broadcast() {
- IntentFilter intent = new IntentFilter();
- intent.addAction(BluetoothDevice.ACTION_FOUND);
- intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
- intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- registerReceiver(searchDevices, intent);
- }
-
- private BroadcastReceiver searchDevices = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
-
- String action = intent.getAction();
- if (BluetoothDevice.ACTION_FOUND.equals(action)) {
- BluetoothDevice device = intent
- .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
- }
- }
- };
(5)蓝牙的配对。
这里我们用到的是java的反射机制。
- private void paireDevice(BluetoothDevice device) {
- try {
- Method createBondMethod = BluetoothDevice.class
- .getMethod("createBond");
- createBondMethod.invoke(device);
- } catch (Exception e) {
-
- e.getStackTrace();
- }
- }
(6)蓝牙的连接服务端和客户端
服务端:这里我声明了四个BluetoothSocket。因为accept()是阻塞操作,一旦连接成功就会返回BluetoothSocket,然后继续等待下一个连接。如此下去我们就实现了多连接。UUID是作为服务端的标识。获得BluetoothSocket后,我们就可以进行相关的操作了,获取输入输出流。进行相互的通信。
- private class AcceptThread extends Thread {
- private final BluetoothServerSocket mmServerSocket;
-
- public AcceptThread() {
-
-
- BluetoothServerSocket tmp = null;
- try {
-
-
- tmp = mBluetoothAdapter
- .listenUsingRfcommWithServiceRecord(
- "eric",
- UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
- } catch (IOException e) {
- }
- mmServerSocket = tmp;
- }
-
- public void run() {
-
- while (true) {
- try {
- Log.d(TAG, "thread is start and accept");
- if (socket == null) {
- socket = mmServerSocket.accept();
- Log.d(TAG, "accept ok");
-
-
- if (socket != null) {
-
-
- Log.d(TAG, "manageConnectedSocket");
- manageConnectedSocket(socket);
-
- }
- }
- if (socket_two == null) {
- Log.d(TAG, "wait two");
- socket_two = mmServerSocket.accept();
- Log.d(TAG, "accept ok");
-
- if (socket != null) {
-
-
- Log.d(TAG, "manageConnectedSocket");
- manageConnectedSocket(socket_two);
- }
- }
- if (socket_three == null) {
- socket_three = mmServerSocket.accept();
- Log.d(TAG, "accept ok");
-
- if (socket != null) {
-
-
- Log.d(TAG, "manageConnectedSocket");
- manageConnectedSocket(socket_three);
- }
- }
- if (socket_four == null) {
- socket_four = mmServerSocket.accept();
- Log.d(TAG, "accept ok");
-
- if (socket != null) {
-
-
- Log.d(TAG, "manageConnectedSocket");
- manageConnectedSocket(socket_four);
- break;
- }
- }
- } catch (IOException e) {
- break;
- }
-
- }
- }
-
-
- public void cancel() {
- try {
- mmServerSocket.close();
- } catch (IOException e) {
- }
- }
-
- private void manageConnectedSocket(BluetoothSocket socket) {
- if (socket!=null) {
- readThread read = new readThread(socket);
- read.start();
- }
- }
- }
客户端:其中的UUID要与服务端的UUID相对应。同理connect()也是阻塞操作。连接成功后即返回BluetoothSocket。
- private class ConnectThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final BluetoothDevice mmDevice;
-
- public ConnectThread(BluetoothDevice device) {
-
-
- BluetoothSocket tmp = null;
- mmDevice = device;
-
-
- try {
-
-
- tmp = device.createRfcommSocketToServiceRecord(UUID
- .fromString("00001101-0000-1000-8000-00805F9B34FB"));
- } catch (IOException e) {
- }
- mmSocket = tmp;
- }
-
- public void run() {
-
- mBluetoothAdapter.cancelDiscovery();
- try {
-
-
- Log.d(TAG, "thread is start and connect");
- mmSocket.connect();
- Log.d(TAG, "connect ok");
- Message msg=mHandler.obtainMessage();
- msg.what=3;
- msg.sendToTarget();
- } catch (IOException connectException) {
-
- Log.d(TAG, "connect throw expection");
- try {
- mmSocket.close();
- } catch (IOException closeException) {
- }
- return;
- }
-
-
- socket=mmSocket;
- if(socket!=null){
- manageConnectedSocket(socket);
- }
- }
-
-
- public void cancel() {
- try {
- socket.close();
- } catch (IOException e) {
- }
- }
-
- private void manageConnectedSocket(BluetoothSocket socket) {
- readThread read = new readThread(socket)
- read.start();
- Log.d(TAG, "the read is start");
- }
- }
数据读入代码:这里我们另起一个线程,当有输入流时就进行获取。这里我们与Handler一起使用,这样就可以在界面及时更新数据。
-
- private class readThread extends Thread {
- private BluetoothSocket socket;
-
- public readThread(BluetoothSocket socket) {
- this.socket = socket;
- }
-
- public void run() {
-
- byte[] buffer = new byte[1024];
- int bytes;
- InputStream mmInStream = null;
- try {
- mmInStream = this.socket.getInputStream();
- } catch (IOException e1) {
-
- e1.printStackTrace();
- }
- while (flag) {
- try {
- Log.d(TAG, "get inputstream");
-
- if ((bytes = mmInStream.read(buffer)) > 0) {
- byte[] buf_data = new byte[bytes];
- for (int i = 0; i < bytes; i++) {
- buf_data[i] = buffer[i];
- }
- String s = new String(buf_data);
- Log.d(TAG, s);
- Message msg = new Message();
- msg.what = 2;
- msg.obj = s;
- mHandler.sendMessage(msg);
- }
- } catch (IOException e) {
- try {
- mmInStream.close();
- } catch (IOException e1) {
-
- e1.printStackTrace();
- }
- break;
- }
- }
- }
- }
发送数据(写入输出流)
这里可能有人不懂为什么这么麻烦。我这写的是服务端群发数据。所有有连接的客户端都能收到。
- private void sendMessage(){
- String s = ed_message.getText().toString()+"";
- if (socket == null) {
- Log.d(TAG, "socket is not connect");
- } else {
- try {
- OutputStream os = socket.getOutputStream();
- os.write(s.getBytes());
- Log.d(TAG, "write to outputstream success,socket");
- } catch (IOException e) {
-
- e.printStackTrace();
- }
- }
-
- if (socket_two == null) {
- Log.d(TAG, "socket_two is not connect");
- } else {
- try {
- OutputStream os = socket_two.getOutputStream();
- os.write(s.getBytes());
- Log.d(TAG, "write to outputstream success,socket_two");
- } catch (IOException e) {
-
- e.printStackTrace();
- }
- }
- if (socket_three == null) {
- Log.d(TAG, "socket_three is not connect");
- } else {
- try {
- OutputStream os = socket_three.getOutputStream();
- os.write(s.getBytes());
- Log.d(TAG, "write to outputstream success,socket_three");
- } catch (IOException e) {
-
- e.printStackTrace();
- }
- }
- if (socket_four == null) {
- Log.d(TAG, "socket_four is not connect");
- } else {
- try {
- OutputStream os = socket_four.getOutputStream();
- os.write(s.getBytes());
- Log.d(TAG, "write to outputstream success,socket_four");
- } catch (IOException e) {
-
- e.printStackTrace();
- }
- }
- }
(7)蓝牙的多连接操作。
代码已在(6)中贴出来了,这里我就解释一下,这里所谓的多连接就是一个服务端和多个客户端。重点就是在服务端一个accept()成功获取BluetoothSocket后,我们要继续监听下一个BluetoothSocket,就像我为什么声明了四个BluetoothSocket(socket,socket_two,socket_three,socket_four);其实没有什么技巧,只要你熟悉socket编程。多试试就OK了。大家可以下载测试Demo进行多次调试。多看看就懂了,而且我的代码还有许多可以改进的地方,大家可以互相讨论学习,路总是人走出来了,如果总吃现成的就永远得不到创新。我这里仅仅做个启发。
Demo代码下载:http://download.csdn.NET/detail/wangwang6233/7188881