[轉載]Android 通訊之藍牙(-)API及通訊方法

   做者:BruceZhangandroid

   出處:http://blog.csdn.net/dlutbrucezhang/article/details/8955104web

                                                        

一般狀況下,咱們對藍牙的操做主要有:開啓和關閉藍牙、搜索周邊設備、能被周邊設備所發現、獲取配對設備、藍牙設備間的數據傳輸。編程

  一、打開藍牙(固然首先要確保你的手機是有藍牙設備的)

  藍牙設備主要分爲兩部分,一部分爲本地設備,另外一部分爲遠程設備。服務器

  • BluetoothAdapter——本地設備,對藍牙操做首先就須要有一個BluetoothAdapter實例。經常使用的幾個方法以下:
    •   cancelDiscovery()——取消本地藍牙設備的搜索操做,若是本地設備正在進行搜索,那麼調用該方法後將中止搜索操做。
    •   Disable()——關閉藍牙設備。
    •   Enable()——打開藍牙設備。相信你們都有過打開藍牙的經歷,通常狀況下都會彈出一個窗口,說正在請求打開藍牙設備,你是否是容許云云。
    •   getAddress()——獲取藍牙設備的MAC地址。
    •   GetDefaultAdapter()——獲取本地的藍牙設備
    •   getName()——獲取本地藍牙的名稱
    •   getRemoteDevice(String address)——根據遠程設備的MAC地址來獲取遠程設備
    •   startDiscovery()——藍牙設備開始搜索周邊設備
  • BuletoothDevice——遠程設備。

    它所包含的方法和BluetoothAdapter同樣,再也不累述。網絡

// 獲取本地的藍牙適配器實例  
             BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();  
             if(adapter!=null)  
             {  
                 if(!adapter.isEnabled())  
                 {  
                     //經過這個方法來請求打開咱們的藍牙設備  
                     Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
                     startActivity(intent);  
                 }  
             }  
             else  
             {  
                 System.out.println("本地設備驅動異常!");  
             }

二、搜索周邊設備

 

  對於Android查找發現藍牙設備使用BluetoothAdapter類的startDiscovery()方法就能夠執行一個異步方式獲取周邊的藍牙設備,由於是一個異步的方法因此咱們不須要考慮線程被阻塞問題,整個過程大約須要12秒時間,這時咱們能夠註冊一個 BroadcastReceiver 對象來接收查找到的藍牙設備信息,咱們經過Filter來過濾ACTION_FOUND這個 Intent動做以獲取每一個遠程設備的詳細信息,經過Intent字段EXTRA_DEVICE 和 EXTRA_CLASS能夠得到包含了每一個BluetoothDevice 對象和對象的該設備類型 BluetoothClass。多線程

  實現一個本身的BroadCastReceiver類,並註冊這個類。app

 private class BluetoothReciever extends BroadcastReceiver {  
   
         @Override  
         public void onReceive(Context context, Intent intent) {  
             // TODO Auto-generated method stub  
             String action = intent.getAction();  
             if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
                 BluetoothDevice device = intent  
                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
                 System.out.println(device.getAddress());  
             }  
         }  
   
     }
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);  
bluetoothReceive = new BluetoothReciever();  
registerReceiver(bluetoothReceive, intentFilter);

由於在註冊一個Receiver後,程序並不知道該什麼時候去回收它,因此須要咱們本身重寫Activity類的onDestroy()方法。異步

protected void onDestroy() {  
         // TODO Auto-generated method stub  
         unregisterReceiver(bluetoothReceive);  
         super.onDestroy();  
     }

三、被周邊設備所發現  

 

  若是須要用戶確認操做,不須要獲取底層藍牙服務實例,能夠經過一個Intent來傳遞ACTION_REQUEST_DISCOVERABLE參數, 這裏經過startActivity來請求開啓。socket

Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
 //50這個參數表明的是藍牙設備能在多少秒內被發現              
 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 50);  
             startActivity(discoverableIntent);

四、配對

  配對操做呢,通常都是發現設備後,由咱們人工來進行選擇後系統自動去配對。咱們能夠經過下面的方法來得到配對的設備:ide

//經過getBondedDevices方法來獲取已經與本設備配對的設備  
                 Set<BluetoothDevice> device= adapter.getBondedDevices();  
                 if(device.size()>0)  
                 {  
                     for(Iterator iterator=device.iterator();iterator.hasNext();)  
                     {  
                         BluetoothDevice bluetoothDevice=(BluetoothDevice)iterator.next();  
                         System.out.println(bluetoothDevice.getAddress());  
                     }  
                 }

五、數據交換  

  在看過前面的啓動、發現/搜索、配對這些操做後,下面來講說數據傳輸的問題。

  在Android系統中,藍牙設備間的數據傳輸問題和咱們在PC上的網絡編程頗爲相似,有一端做爲Server端監聽Client端的鏈接請求,在兩者創建了鏈接後,就可使用普通的數據傳輸方式進行數據交換操做了。在這個過程當中,我須要使用到BluetoothServerSocket和BluetoothSocket兩個類來創建Server端和Client端,還須要使用到一些關於流(Stream)的知識。

  • BluetoothServerSocket——服務端(監聽端、監聽器、接受請求的一端)
    • Accept()——阻塞宿主線程,直至收到客戶端請求。返回BluetoothSocket對象。因爲這個
    • Accept(int timeout)——阻塞宿主線程,直至收到客戶端請求或等待時間超過timeout。返回BluetoothSocket對象。
    • Close()——關閉BluetoothServerSocket監聽器。

  能夠看到,Accept方法是一個阻塞方法,因此在進行開發的時候,通常都須要用到多線程的知識。JAVA的多線程知識,能夠在JAVA的JDK幫助文檔中查看,就單純的應用來講仍是比較簡單的。

  • BluetoothSocket——客戶端(請求端)
    • Close()——關閉BluetoothSocket請求端。
    • Connect()——主動向服務端(監聽端)發起鏈接請求。

  在瞭解了這兩個類後,能夠着手來創建咱們本身的Server端和Client端了。

  若是一個設備須要和兩個或多個設備鏈接時,就須要做爲一個server來傳輸,服務器端套接字在接受(accepted) 一個客戶發來的BluetoothSocket鏈接請求時做出相應的響應。服務器socket將監聽進入的鏈接請求,一旦鏈接被接受,將產生一個BluetoothSocket。

  • 建立一個Server

  使用BluetoothAdapter類的listenUsingRfcommWithServiceRecord方法來新建一個ServerSocket。在listenUsingRfcommWithServiceRecord中有一個參數叫作UUID,UUID(Universally Unique Identifier)是一個128位的字符串ID,被用於惟一標識咱們的藍牙服務。你可使用web上的任何一款UUID產生器爲你的程序獲取一個UUID,而後使用fromString(String)初始化一個UUID。

  使用ServerSocket實例的accept方法進行監聽,當監聽到帶有咱們初始化的UUID參數的鏈接請求後做出響應,鏈接成功後返回一個BluetoothSocket對象。鏈接完成後,調用close方法關閉該Socket監聽。

 // Bluetooth的ServerSocket包裝類  
     class BluetoothServer {  
         public BluetoothServer() throws IOException {  
         }  
   
         // 要創建一個ServerSocket對象,須要使用adapter.listenUsingRfcommWithServiceRecord方法  
 // UUID能夠在網上去申請  
         private BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myServerSocket",  
                         UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04"));  
         BluetoothSocket socket = serverSocket.accept();  
   
         void m() throws IOException {  
             if (socket != null) {  
                 InputStream inputStream = socket.getInputStream();  
                 int read = -1;  
                 final byte[] bytes = new byte[1024];  
                 for (; (read = inputStream.read(bytes)) > -1;) {  
                     final int count = read;  
                     Thread _start = new Thread(new Runnable() {  
   
                         @Override  
                         public void run() {   
                             // TODO Auto-generated method stub  
                             StringBuilder sb = new StringBuilder();  
                             for (int i = 0; i < count; i++) {  
                                 if (i > 0) {  
                                     sb.append(' ');  
                                 }  
                                 String _s = Integer.toHexString(bytes[i] & 0xFF);  
                                 if (_s.length() < 2) {  
                                     sb.append('0');  
                                 }  
                                 sb.append(_s);  
                             }  
                             System.out.println(sb.toString());  
                         }  
                     });  
                     _start.start();  
                 }  
             }  
         }  
     }
  • 建立一個Client

  建立一個Client端,首先須要咱們使用BluetoothDevice的實例的createRfcommSocketToServiceRecord方法來建立一個BluetoothSocket實例。在建立的時候,須要給createRfcommSocketToServiceRecord方法傳入咱們服務端的UUID值。而後使用BluetoothSocket實例的Connect方法對Server端進行鏈接請求,當鏈接成功後,Client端和Server端的傳輸通道就被打開。最後在鏈接完成後使用該實例的close方法來關閉這個鏈接。

class BluetoothClient {  
         BluetoothDevice device = null;  
   
         //經過構造函數來傳入一個BluetoothDevice實例  
         public BluetoothClient(BluetoothDevice device) {  
             this.device = device;  
         }  
         BluetoothSocket socket = null;  
         void connetServer() throws IOException {  
             Thread _clientThread = new Thread(new Runnable() {  
                 public void run() {  
                     try {  
                         //經過BluetoothDevice實例的createRfcommSocketToServiceRecord方法能夠返回一個帶有UUID的BluetoothSocket實例  
                         socket = device.createRfcommSocketToServiceRecord(UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04"));  
                     } catch (IOException e1) {   
                         // TODO Auto-generated catch block  
                         e1.printStackTrace();  
                     }  
                     try {  
                         socket.connect();  
                     } catch (IOException e1) {   
                         // TODO Auto-generated catch block  
                         e1.printStackTrace();  
                     }  
                     if (socket != null) {  
                         try {  
                             socket.close();  
                         } catch (Exception e) {  
                             // TODO: handle exception  
                         }  
                     }  
                 }  
             });  
             _clientThread.start();  
         }  
     

getInputStream()——得到一個可讀的流,該流在鏈接不成功的狀況下依舊能夠得到,可是對其操做的話就會報IOException的異常。須要從外部獲取的數據都從該流中獲取。

  getOutputStrem()——得到一個可寫的流,該流在鏈接不成功的狀況下依舊能夠得到,可是對其操做的話就會報IOException的異常。須要往外部傳輸的數據均可以寫到該流中傳輸出去。

  數據傳輸的大體流程以下:

    • 首先,分別經過getInputStream()和getOutputStream()得到管理數據傳輸的InputStream和OutputStream。
    • 而後,開闢一個線程專門用於數據的讀或寫。這是很是重要的,由於read(byte[])和write(byte[])方法都是阻塞調用。read(byte[])從輸入流(InputStream)中讀取數據。write(byte[])將數據寫入到OutputStream流中去,這個方法通常不會阻塞,但當遠程設備的中間緩衝區已滿而對方沒有及時地調用read(byte[])時將會一直阻塞。因此,新開闢的線程中的主循環將一直用於從InputStream中讀取數據。

  還要補充一點,因爲藍牙設備是系統設備,因此須要有相應的權限支持。在AndroidManifest.xml文件中添加上權限。

<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>  
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
相關文章
相關標籤/搜索