Android蓝牙高级操作(多连接)

最近一直在做与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_BONDEDBOND_BONDINGBOND_NONE分别是已绑定,绑定中、未绑定。

BluetoothServerSocket:这是服务端,通过accept()返回BluetoothSocket。既然是Socket相信大家都再熟悉不过了吧!如果你不太清楚socket编程,那就先去看Java基础吧!这里我也不能偏题。

BluetoothSocket:这是客户端,connect()与服务端进行连接。通过它回去输入输出流。

(2)蓝牙的开启和关闭。

打开蓝牙:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void startBluetooth() {  
  2.         if (mBluetoothAdapter == null) {  
  3.             // 表明此手机不支持蓝牙  
  4.             Log.d(TAG, "device is not supported bluebooth");  
  5.             return;  
  6.         }  
  7.         if (!mBluetoothAdapter.isEnabled()) { // 蓝牙未开启,则开启蓝牙  
  8.             mBluetoothAdapter.enable();  
  9.         }  
  10.     }  
关闭蓝牙:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {  
  2.                     mBluetoothAdapter.disable();  
  3.                 }  
(3) 设置设备可被搜索。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 使本机蓝牙在300秒内可被搜索  
  2.     private void ensureDiscoverable() {  
  3.         if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {  
  4.             Intent discoverableIntent = new Intent(  
  5.                     BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
  6.             discoverableIntent.putExtra(  
  7.                     BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//设置被发现时间  
  8.             startActivity(discoverableIntent);  
  9.         }  
  10.     }  
(4) 搜索设备及广播接收器的注册。

记得在onCreate()中注册,在onDestory()中unregisterReceiver(searchDevices);这是android广播机制的基础,不懂的可以回去看看android广播基础了。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void register2Broadcast() {  
  2.         IntentFilter intent = new IntentFilter();  
  3.         intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果  
  4.         intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);  
  5.         intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);  
  6.         intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);  
  7.         registerReceiver(searchDevices, intent);  
  8.     }  
  9.   
  10.     private BroadcastReceiver searchDevices = new BroadcastReceiver() {  
  11.   
  12.         @Override  
  13.         public void onReceive(Context context, Intent intent) {  
  14.             // TODO Auto-generated method stub  
  15.             String action = intent.getAction();  
  16.             if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
  17.                 BluetoothDevice device = intent  
  18.                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
  19.                 //addDevice2List(device); 获取BluetoothDevice后剩下的自己处理了   
  20.             }  
  21.         }  
  22.     };  
(5)蓝牙的配对。

这里我们用到的是java的反射机制。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void paireDevice(BluetoothDevice device) {  
  2.         try {  
  3.             Method createBondMethod = BluetoothDevice.class  
  4.                     .getMethod("createBond");  
  5.             createBondMethod.invoke(device);  
  6.         } catch (Exception e) {  
  7.             // TODO: handle exception  
  8.             e.getStackTrace();  
  9.         }  
  10.     }  
(6)蓝牙的连接服务端和客户端

服务端:这里我声明了四个BluetoothSocket。因为accept()是阻塞操作,一旦连接成功就会返回BluetoothSocket,然后继续等待下一个连接。如此下去我们就实现了多连接。UUID是作为服务端的标识。获得BluetoothSocket后,我们就可以进行相关的操作了,获取输入输出流。进行相互的通信。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private class AcceptThread extends Thread {  
  2.         private final BluetoothServerSocket mmServerSocket;  
  3.   
  4.         public AcceptThread() {  
  5.             // Use a temporary object that is later assigned to mmServerSocket,  
  6.             // because mmServerSocket is final  
  7.             BluetoothServerSocket tmp = null;  
  8.             try {  
  9.                 // MY_UUID is the app's UUID string, also used by the client  
  10.                 // code  
  11.                 tmp = mBluetoothAdapter  
  12.                         .listenUsingRfcommWithServiceRecord(  
  13.                                 "eric",  
  14.                                 UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));  
  15.             } catch (IOException e) {  
  16.             }  
  17.             mmServerSocket = tmp;  
  18.         }  
  19.   
  20.         public void run() {  
  21.             // Keep listening until exception occurs or a socket is returned  
  22.             while (true) {  
  23.                 try {  
  24.                     Log.d(TAG, "thread is start and accept");  
  25.                     if (socket == null) {  
  26.                         socket = mmServerSocket.accept();  
  27.                         Log.d(TAG, "accept ok");  
  28.                           
  29.                         // If a connection was accepted  
  30.                         if (socket != null) {  
  31.                             // Do work to manage the connection (in a separate  
  32.                             // thread)  
  33.                             Log.d(TAG, "manageConnectedSocket");  
  34.                             manageConnectedSocket(socket);//相关处理函数  
  35.                             // break;  
  36.                         }  
  37.                     }  
  38.                     if (socket_two == null) {  
  39.                         Log.d(TAG, "wait two");  
  40.                         socket_two = mmServerSocket.accept();  
  41.                         Log.d(TAG, "accept ok");  
  42.                         // If a connection was accepted  
  43.                         if (socket != null) {  
  44.                             // Do work to manage the connection (in a separate  
  45.                             // thread)  
  46.                             Log.d(TAG, "manageConnectedSocket");  
  47.                             manageConnectedSocket(socket_two);  
  48.                         }  
  49.                     }  
  50.                     if (socket_three == null) {  
  51.                         socket_three = mmServerSocket.accept();  
  52.                         Log.d(TAG, "accept ok");  
  53.                         // If a connection was accepted  
  54.                         if (socket != null) {  
  55.                             // Do work to manage the connection (in a separate  
  56.                             // thread)  
  57.                             Log.d(TAG, "manageConnectedSocket");  
  58.                             manageConnectedSocket(socket_three);  
  59.                         }  
  60.                     }  
  61.                     if (socket_four == null) {  
  62.                         socket_four = mmServerSocket.accept();  
  63.                         Log.d(TAG, "accept ok");  
  64.                         // If a connection was accepted  
  65.                         if (socket != null) {  
  66.                             // Do work to manage the connection (in a separate  
  67.                             // thread)  
  68.                             Log.d(TAG, "manageConnectedSocket");  
  69.                             manageConnectedSocket(socket_four);  
  70.                             break;  
  71.                         }  
  72.                     }  
  73.                 } catch (IOException e) {  
  74.                     break;  
  75.                 }  
  76.   
  77.             }  
  78.         }  
  79.   
  80.         /** Will cancel the listening socket, and cause the thread to finish */  
  81.         public void cancel() {  
  82.             try {  
  83.                 mmServerSocket.close();  
  84.             } catch (IOException e) {  
  85.             }  
  86.         }  
  87.   
  88.         private void manageConnectedSocket(BluetoothSocket socket) {  
  89.             if (socket!=null) {  
  90.                 readThread read = new readThread(socket);  
  91.                 read.start();  
  92.             }   
  93.         }  
  94.     }  
客户端:其中的UUID要与服务端的UUID相对应。同理connect()也是阻塞操作。连接成功后即返回BluetoothSocket。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private class ConnectThread extends Thread {  
  2.         private final BluetoothSocket mmSocket;  
  3.         private final BluetoothDevice mmDevice;  
  4.   
  5.         public ConnectThread(BluetoothDevice device) {  
  6.             // Use a temporary object that is later assigned to mmSocket,  
  7.             // because mmSocket is final  
  8.             BluetoothSocket tmp = null;  
  9.             mmDevice = device;  
  10.   
  11.             // Get a BluetoothSocket to connect with the given BluetoothDevice  
  12.             try {  
  13.                 // MY_UUID is the app's UUID string, also used by the server  
  14.                 // code  
  15.                 tmp = device.createRfcommSocketToServiceRecord(UUID  
  16.                         .fromString("00001101-0000-1000-8000-00805F9B34FB"));  
  17.             } catch (IOException e) {  
  18.             }  
  19.             mmSocket = tmp;  
  20.         }  
  21.   
  22.         public void run() {  
  23.             // Cancel discovery because it will slow down the connection  
  24.             mBluetoothAdapter.cancelDiscovery();  
  25.             try {  
  26.                 // Connect the device through the socket. This will block  
  27.                 // until it succeeds or throws an exception  
  28.                 Log.d(TAG, "thread is start and connect");  
  29.                 mmSocket.connect();  
  30.                 Log.d(TAG, "connect ok");  
  31.                 Message msg=mHandler.obtainMessage();  
  32.                 msg.what=3;  
  33.                 msg.sendToTarget();  
  34.             } catch (IOException connectException) {  
  35.                 // Unable to connect; close the socket and get out  
  36.                 Log.d(TAG, "connect throw expection");  
  37.                 try {  
  38.                     mmSocket.close();  
  39.                 } catch (IOException closeException) {  
  40.                 }  
  41.                 return;  
  42.             }  
  43.   
  44.             // Do work to manage the connection (in a separate thread)  
  45.             socket=mmSocket;  
  46.             if(socket!=null){  
  47.                 manageConnectedSocket(socket);  
  48.             }  
  49.         }  
  50.   
  51.         /** Will cancel an in-progress connection, and close the socket */  
  52.         public void cancel() {  
  53.             try {  
  54.                 socket.close();  
  55.             } catch (IOException e) {  
  56.             }  
  57.         }  
  58.   
  59.         private void manageConnectedSocket(BluetoothSocket socket) {  
  60.             readThread read = new readThread(socket)//开启读取数据线程;  
  61.             read.start();  
  62.             Log.d(TAG, "the read is start");  
  63.         }  
  64.     }  
数据读入代码:这里我们另起一个线程,当有输入流时就进行获取。这里我们与Handler一起使用,这样就可以在界面及时更新数据。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 读取数据  
  2.     private class readThread extends Thread {  
  3.         private BluetoothSocket socket;  
  4.   
  5.         public readThread(BluetoothSocket socket) {  
  6.             this.socket = socket;  
  7.         }  
  8.   
  9.         public void run() {  
  10.   
  11.             byte[] buffer = new byte[1024];  
  12.             int bytes;  
  13.             InputStream mmInStream = null;  
  14.             try {  
  15.                 mmInStream = this.socket.getInputStream();  
  16.             } catch (IOException e1) {  
  17.                 // TODO Auto-generated catch block  
  18.                 e1.printStackTrace();  
  19.             }  
  20.             while (flag) {  
  21.                 try {  
  22.                     Log.d(TAG, "get inputstream");  
  23.                     // Read from the InputStream  
  24.                     if ((bytes = mmInStream.read(buffer)) > 0) {  
  25.                         byte[] buf_data = new byte[bytes];  
  26.                         for (int i = 0; i < bytes; i++) {  
  27.                             buf_data[i] = buffer[i];  
  28.                         }  
  29.                         String s = new String(buf_data);  
  30.                         Log.d(TAG, s);  
  31.                         Message msg = new Message();  
  32.                         msg.what = 2;  
  33.                         msg.obj = s;  
  34.                         mHandler.sendMessage(msg);  
  35.                     }  
  36.                 } catch (IOException e) {  
  37.                     try {  
  38.                         mmInStream.close();  
  39.                     } catch (IOException e1) {  
  40.                         // TODO Auto-generated catch block  
  41.                         e1.printStackTrace();  
  42.                     }  
  43.                     break;  
  44.                 }  
  45.             }  
  46.         }  
  47.     }  
发送数据(写入输出流)

这里可能有人不懂为什么这么麻烦。我这写的是服务端群发数据。所有有连接的客户端都能收到。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void sendMessage(){  
  2.         String s = ed_message.getText().toString()+"";  
  3.         if (socket == null) {  
  4.             Log.d(TAG, "socket is not connect");  
  5.         } else {  
  6.             try {  
  7.                 OutputStream os = socket.getOutputStream();  
  8.                 os.write(s.getBytes());  
  9.                 Log.d(TAG, "write to outputstream success,socket");  
  10.             } catch (IOException e) {  
  11.                 // TODO Auto-generated catch block  
  12.                 e.printStackTrace();  
  13.             }  
  14.         }  
  15.   
  16.         if (socket_two == null) {  
  17.             Log.d(TAG, "socket_two is not connect");  
  18.         } else {  
  19.             try {  
  20.                 OutputStream os = socket_two.getOutputStream();  
  21.                 os.write(s.getBytes());  
  22.                 Log.d(TAG, "write to outputstream success,socket_two");  
  23.             } catch (IOException e) {  
  24.                 // TODO Auto-generated catch block  
  25.                 e.printStackTrace();  
  26.             }  
  27.         }  
  28.         if (socket_three == null) {  
  29.             Log.d(TAG, "socket_three is not connect");  
  30.         } else {  
  31.             try {  
  32.                 OutputStream os = socket_three.getOutputStream();  
  33.                 os.write(s.getBytes());  
  34.                 Log.d(TAG, "write to outputstream success,socket_three");  
  35.             } catch (IOException e) {  
  36.                 // TODO Auto-generated catch block  
  37.                 e.printStackTrace();  
  38.             }  
  39.         }  
  40.         if (socket_four == null) {  
  41.             Log.d(TAG, "socket_four is not connect");  
  42.         } else {  
  43.             try {  
  44.                 OutputStream os = socket_four.getOutputStream();  
  45.                 os.write(s.getBytes());  
  46.                 Log.d(TAG, "write to outputstream success,socket_four");  
  47.             } catch (IOException e) {  
  48.                 // TODO Auto-generated catch block  
  49.                 e.printStackTrace();  
  50.             }  
  51.         }  
  52.     }  
(7)蓝牙的多连接操作。

代码已在(6)中贴出来了,这里我就解释一下,这里所谓的多连接就是一个服务端和多个客户端。重点就是在服务端一个accept()成功获取BluetoothSocket后,我们要继续监听下一个BluetoothSocket,就像我为什么声明了四个BluetoothSocket(socket,socket_two,socket_three,socket_four);其实没有什么技巧,只要你熟悉socket编程。多试试就OK了。大家可以下载测试Demo进行多次调试。多看看就懂了,而且我的代码还有许多可以改进的地方,大家可以互相讨论学习,路总是人走出来了,如果总吃现成的就永远得不到创新。我这里仅仅做个启发。

Demo代码下载:http://download.csdn.NET/detail/wangwang6233/7188881

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值