1. 程式人生 > 其它 >藍芽通訊測試app之藍芽通訊(二)

藍芽通訊測試app之藍芽通訊(二)

藍芽通訊開發流程

為了讓兩個裝置上的兩個應用程式之間建立連線,你必須同時實現服務端和客戶端機制。

  • 服務端:使用的是 BluetoothServerSocket 類,並且呼叫的是 listenUsingRfcommWithServiceRecord(string,UUID) 方法來獲得一個BluetoothServerSocket物件。
  • 客戶端:使用的是 BluetoothSocket 類,呼叫的是 createRfcommSocketToServiceRecord(UUID) 方法,這裡的 UUID 會和服務端的UUID進行比較,如果匹配就能獲得一個BluetoothSocket 物件。
  • 公共端:在連線後,都會進入已連線執行緒。會在這個執行緒中進行寫入和讀取。

經典藍芽連線相當於socket連線,是個非常耗時的操作,所以應該放到子執行緒中去完成。

服務端的監聽執行緒:

// 建立監聽執行緒,準備接受新連線。使用阻塞方式,呼叫BluetoothServerSocket.accept()
private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;
    public AcceptThread(){
        BluetoothServerSocket tmp = null;
        try{
            //MY_UUID用於唯一標識當前的藍芽服務,在建立連線時會被客戶端使用
            tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
        }catch (IOException e){}
        mmServerSocket = tmp;
    }
    public void run(){
        BluetoothSocket socket= null;
        while(mState != STATE_CONNECTED){
            try{
                // 保持監聽狀態,並阻塞執行緒,當連線建立時返回。
                socket = mmServerSocket.accept();
            }catch (IOException e) {
                break;
            }
            if(socket != null){
                //在單獨的執行緒中對連線進行管理,本執行緒結束
                ConnectedThread mConnectedThread = new ConnectedThread(socket);
                mConnectedThread.start();
                try{
                    mmServerSocket.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    public void cancel(){
        try{
            mmServerSocket.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

客戶端的連線執行緒:

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    public ConnectThread(BluetoothDevice device){
        Log.e("ChatTag", " -- ConnectThread -- ");
        mmDevice=device;
        BluetoothSocket tmp = null;
        //獲取一個 BluetoothSocket 以連線給定的 BluetoothDevice
        try{
            // MY_UUID 是應用程式的 UUID 字串,也由伺服器程式碼使用
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        }catch (IOException e){
            e.printStackTrace();
        }
        mmSocket = tmp;
    }

    public void run(){
        // 取消發現,因為它會減慢連線速度
        mAdapter.cancelDiscovery();
        try{
            // 請求連線,該操作會阻塞執行緒
            // 直到成功或丟擲異常
            mmSocket.connect();
        }catch (IOException e){
            e.printStackTrace();
            // Unable to connect; close the socket and get out
            try{
                mmSocket.close();
            }catch (IOException e2){}
            //ChatService.this.start();
            return;
        }
        synchronized(ChatService.this){
            mConnectedThread = null;
        }
        // 連線已建立,在單獨的執行緒中對連線進行管理
        ConnectedThread mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.start();
    }

    public void cancel(){
        /* try{
            mmSocket.close();
        }catch (IOException e){}*/
    }
}

公共端的已連線執行緒:

// 雙方藍芽連線後一直執行的執行緒。建構函式中設定輸入輸出流
// Run方法中使用阻塞模式的Inputstream.read()迴圈讀取輸入流
private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private  InputStream mmInStream;
    private  OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket){
        Log.e("ChatTag", " -- ConnectedThread -- ");
        mmSocket = socket;
        // 使用臨時物件獲取輸入和輸出流
        try{
            mmInStream = mmSocket.getInputStream();
            mmOutStream = mmSocket.getOutputStream();
        }catch (IOException e){}
    }

    public void run(){
        byte[]buffer=new byte[1024];
        int bytes;
        //讀資料需要不斷監聽 ,寫 不需要
        while (true) {
            try {
                //讀取 InputStream 的資料
                bytes = mmInStream.read(buffer);
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }

    public void write(byte[]buffer){
        try{
            mmOutStream.write(buffer);
        }catch (IOException e){
             e.printStackTrace();
        }
    }

    public void cancel(){
        try{
            mmSocket.close();
        }catch (IOException e){}
    }
}

呼叫流程

  • 在 主檢視 的 onResume () 方法中,呼叫監聽執行緒,等著被連線。

  • 在藍芽配對的流程中,在配對後會將配對的藍芽裝置地址 放入 Intent;

  • 在 主檢視 的 onActivityResult () 方法中,能從 Intent 中獲取藍芽裝置地址

    // 獲取 藍芽介面卡
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    // 通過藍芽裝置地址,獲取 藍芽裝置
    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    
    // 然後呼叫連線執行緒,進行連線
    ConnectThread mConnectThread = new ConnectThread(device);
    mConnectThread.start();
    
  • 然後呼叫連線執行緒,請求連線服務端

  • 當連線通過後,客戶端和服務端就可以進行通訊了。