成功連線至藍牙裝置後,每個裝置都有連線的 BluetoothSocket
。您現在可以在裝置間分享資訊。使用 BluetoothSocket
時,資料的一般轉移程序如下:
分別使用
getInputStream()
和getOutputStream()
取得用於透過通訊端處理傳輸的InputStream
和OutputStream
。使用
read(byte[])
和write(byte[])
將資料讀取並寫入串流。
當然需要考量實作詳情。請特別注意,您應該使用專屬執行緒從串流讀取及寫入串流。由於 read(byte[])
和 write(byte[])
方法都會封鎖呼叫,因此這一點相當重要。read(byte[])
方法會封鎖,直到有待從串流讀取的內容為止。write(byte[])
方法通常不會封鎖,但如果遠端裝置呼叫 read(byte[])
的速度不夠快,且中繼緩衝區因此已滿,則該方法可能會封鎖流量控制。因此,您應在執行緒中設計主要迴圈,以便從 InputStream
讀取。您可以在執行緒中另外使用公開方法,來啟動對 OutputStream
的寫入作業。
範例
以下範例說明如何在兩部透過藍牙連線的裝置之間傳輸資料:
Kotlin
private const val TAG = "MY_APP_DEBUG_TAG" // Defines several constants used when transmitting messages between the // service and the UI. const val MESSAGE_READ: Int = 0 const val MESSAGE_WRITE: Int = 1 const val MESSAGE_TOAST: Int = 2 // ... (Add other message types here as needed.) class MyBluetoothService( // handler that gets info from Bluetooth service private val handler: Handler) { private inner class ConnectedThread(private val mmSocket: BluetoothSocket) : Thread() { private val mmInStream: InputStream = mmSocket.inputStream private val mmOutStream: OutputStream = mmSocket.outputStream private val mmBuffer: ByteArray = ByteArray(1024) // mmBuffer store for the stream override fun run() { var numBytes: Int // bytes returned from read() // Keep listening to the InputStream until an exception occurs. while (true) { // Read from the InputStream. numBytes = try { mmInStream.read(mmBuffer) } catch (e: IOException) { Log.d(TAG, "Input stream was disconnected", e) break } // Send the obtained bytes to the UI activity. val readMsg = handler.obtainMessage( MESSAGE_READ, numBytes, -1, mmBuffer) readMsg.sendToTarget() } } // Call this from the main activity to send data to the remote device. fun write(bytes: ByteArray) { try { mmOutStream.write(bytes) } catch (e: IOException) { Log.e(TAG, "Error occurred when sending data", e) // Send a failure message back to the activity. val writeErrorMsg = handler.obtainMessage(MESSAGE_TOAST) val bundle = Bundle().apply { putString("toast", "Couldn't send data to the other device") } writeErrorMsg.data = bundle handler.sendMessage(writeErrorMsg) return } // Share the sent message with the UI activity. val writtenMsg = handler.obtainMessage( MESSAGE_WRITE, -1, -1, mmBuffer) writtenMsg.sendToTarget() } // Call this method from the main activity to shut down the connection. fun cancel() { try { mmSocket.close() } catch (e: IOException) { Log.e(TAG, "Could not close the connect socket", e) } } } }
Java
public class MyBluetoothService { private static final String TAG = "MY_APP_DEBUG_TAG"; private Handler handler; // handler that gets info from Bluetooth service // Defines several constants used when transmitting messages between the // service and the UI. private interface MessageConstants { public static final int MESSAGE_READ = 0; public static final int MESSAGE_WRITE = 1; public static final int MESSAGE_TOAST = 2; // ... (Add other message types here as needed.) } private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; private byte[] mmBuffer; // mmBuffer store for the stream public ConnectedThread(BluetoothSocket socket) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams; using temp objects because // member streams are final. try { tmpIn = socket.getInputStream(); } catch (IOException e) { Log.e(TAG, "Error occurred when creating input stream", e); } try { tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "Error occurred when creating output stream", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { mmBuffer = new byte[1024]; int numBytes; // bytes returned from read() // Keep listening to the InputStream until an exception occurs. while (true) { try { // Read from the InputStream. numBytes = mmInStream.read(mmBuffer); // Send the obtained bytes to the UI activity. Message readMsg = handler.obtainMessage( MessageConstants.MESSAGE_READ, numBytes, -1, mmBuffer); readMsg.sendToTarget(); } catch (IOException e) { Log.d(TAG, "Input stream was disconnected", e); break; } } } // Call this from the main activity to send data to the remote device. public void write(byte[] bytes) { try { mmOutStream.write(bytes); // Share the sent message with the UI activity. Message writtenMsg = handler.obtainMessage( MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer); writtenMsg.sendToTarget(); } catch (IOException e) { Log.e(TAG, "Error occurred when sending data", e); // Send a failure message back to the activity. Message writeErrorMsg = handler.obtainMessage(MessageConstants.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString("toast", "Couldn't send data to the other device"); writeErrorMsg.setData(bundle); handler.sendMessage(writeErrorMsg); } } // Call this method from the main activity to shut down the connection. public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close the connect socket", e); } } } }
在建構函式取得必要的串流後,執行緒會等待資料透過 InputStream
傳送。當 read(byte[])
傳回來自串流的資料時,系統會使用父項類別的成員 Handler
,將資料傳送至主要活動。執行緒會等待更多從 InputStream
讀取的位元組。
如要傳送傳出資料,請從主要活動呼叫執行緒的 write()
方法,然後傳入要傳送的位元組。這個方法會呼叫 write(byte[])
以將資料傳送至遠端裝置。如果在呼叫 write(byte[])
時擲回 IOException
,執行緒會將浮動式訊息傳送至主要活動,向使用者說明裝置無法將指定位元組傳送到其他 (已連線) 裝置。
執行緒的 cancel()
方法可讓您隨時關閉 BluetoothSocket
,藉此終止連線。使用藍牙連線後,請一律呼叫此方法。
如需藍牙 API 的使用示範,請參閱 GitHub 上的藍牙即時通訊範例應用程式。