藍芽通訊測試app之藍芽通訊(二)
阿新 • • 發佈:2021-06-15
藍芽通訊開發流程
為了讓兩個裝置上的兩個應用程式之間建立連線,你必須同時實現服務端和客戶端機制。
- 服務端:使用的是 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();
-
然後呼叫連線執行緒,請求連線服務端
-
當連線通過後,客戶端和服務端就可以進行通訊了。