1. 程式人生 > >Android藍芽高階操作(多連線)

Android藍芽高階操作(多連線)

最近一直在做與bluetooth相關的應用。主要涉及Android手機藍芽的多連線問題。網上幾乎沒有與藍芽多連線相關的具體實現資料,所以我開始從android的官方文件入手,大半夜的一個人坐下面看那英文文件,真TMD不是滋味,現在回想下當年做的英語閱讀理解真似一坨shit。不過功夫不負有心人,終於搞清楚了它的構架和通訊模式。這裡我先講bluetooth的基本操作,然後再深入講解它的多連線問題(大家期待的重頭戲)。注意:我這裡主要講的是多連線的核心實現,至於藍芽的一些基礎操作,我只是簡單的介紹。如果有不懂的可以參考其他資料。我也做了一個測試Demo,裡面的程式碼基本參考的官方文件,若有疑問可以去官網上看看。我試過一次可以連線三個手機。當然這不一定是極限資料,因為裝置有限。有條件的朋友可以修改下程式碼,做下壓力測試。

流程:

(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)藍芽的開啟和關閉。

開啟藍芽:

  1. privatevoid 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.     }  
關閉藍芽:
  1. if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {  
  2.                     mBluetoothAdapter.disable();  
  3.                 }  
(3)設定裝置可被搜尋。
  1. // 使本機藍芽在300秒內可被搜尋
  2.     privatevoid 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廣播基礎了。

  1. privatevoid 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.     private BroadcastReceiver searchDevices = new BroadcastReceiver() {  
  10.         @Override
  11.         publicvoid onReceive(Context context, Intent intent) {  
  12.             // TODO Auto-generated method stub
  13.             String action = intent.getAction();  
  14.             if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
  15.                 BluetoothDevice device = intent  
  16.                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
  17.                 //addDevice2List(device); 獲取BluetoothDevice後剩下的自己處理了 
  18.             }  
  19.         }  
  20.     };  
(5)藍芽的配對。

這裡我們用到的是java的反射機制。

  1. privatevoid 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後,我們就可以進行相關的操作了,獲取輸入輸出流。進行相互的通訊。

  1. privateclass AcceptThread extends Thread {  
  2.         privatefinal BluetoothServerSocket mmServerSocket;  
  3.         public AcceptThread() {  
  4.             // Use a temporary object that is later assigned to mmServerSocket,
  5.             // because mmServerSocket is final
  6.             BluetoothServerSocket tmp = null;  
  7.             try {  
  8.                 // MY_UUID is the app's UUID string, also used by the client
  9.                 // code
  10.                 tmp = mBluetoothAdapter  
  11.                         .listenUsingRfcommWithServiceRecord(  
  12.                                 "eric",  
  13.                                 UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));  
  14.             } catch (IOException e) {  
  15.             }  
  16.             mmServerSocket = tmp;  
  17.         }  
  18.         publicvoid run() {  
  19.             // Keep listening until exception occurs or a socket is returned
  20.             while (true) {  
  21.                 try {  
  22.                     Log.d(TAG, "thread is start and accept");  
  23.                     if (socket == null) {  
  24.                         socket = mmServerSocket.accept();  
  25.                         Log.d(TAG, "accept ok");  
  26.                         // If a connection was accepted
  27.                         if (socket != null) {  
  28.                             // Do work to manage the connection (in a separate
  29.                             // thread)
  30.                             Log.d(TAG, "manageConnectedSocket");  
  31.                             manageConnectedSocket(socket);//相關處理函式
  32.                             // break;
  33.                         }  
  34.                     }  
  35.                     if (socket_two == null) {  
  36.                         Log.d(TAG, "wait two");  
  37.                         socket_two = mmServerSocket.accept();  
  38.                         Log.d(TAG, "accept ok");  
  39.                         // If a connection was accepted
  40.                         if (socket != null) {