Bluetooth-Daten übertragen

Nachdem Sie eine Verbindung zu einem Bluetooth-Gerät hergestellt haben, ist jedes dieser Geräte mit einem BluetoothSocket verbunden. Sie können jetzt Informationen zwischen Geräten teilen. Mit BluetoothSocket werden Daten im Allgemeinen so übertragen:

  1. Rufen Sie die InputStream und OutputStream ab, die Übertragungen über den Socket verarbeiten, indem Sie getInputStream() bzw. getOutputStream() verwenden.

  2. Daten in den Streams lesen und schreiben mit read(byte[]) und write(byte[]).

Natürlich müssen Details zur Implementierung berücksichtigt werden. Sie sollten insbesondere einen speziellen Thread verwenden, um aus dem Stream zu lesen und darin zu schreiben. Das ist wichtig, da sowohl die Methode read(byte[]) als auch write(byte[]) Aufrufe blockieren. Die Methode read(byte[]) wird blockiert, bis etwas aus dem Stream gelesen werden kann. Die Methode write(byte[]) wird normalerweise nicht blockiert, kann aber für die Ablaufsteuerung blockiert werden, wenn das Remote-Gerät read(byte[]) nicht schnell genug aufruft und dadurch die Zwischenzwischenspeicher voll werden. Daher sollten Sie Ihre Hauptschleife im Thread dem Lesen aus InputStream zuweisen. Sie können eine separate öffentliche Methode im Thread verwenden, um Schreibvorgänge für OutputStream zu initiieren.

Beispiel

Das folgende Beispiel zeigt, wie Sie Daten zwischen zwei über Bluetooth verbundenen Geräten übertragen können:

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);
           }
       }
   }
}

Nachdem der Konstruktor die erforderlichen Streams abgerufen hat, wartet der Thread darauf, dass Daten über InputStream ankommen. Wenn read(byte[]) mit Daten aus dem Stream zurückkehrt, werden die Daten mithilfe eines Mitglieds Handler aus der übergeordneten Klasse an die Hauptaktivität gesendet. Der Thread wartet dann, bis weitere Byte aus InputStream gelesen wurden.

Zum Senden ausgehender Daten rufen Sie die Methode write() des Threads aus der Hauptaktivität auf und übergeben die zu sendenden Byte. Diese Methode ruft write(byte[]) auf, um die Daten an das Remote-Gerät zu senden. Wenn beim Aufrufen von write(byte[]) ein IOException ausgelöst wird, sendet der Thread eine Meldung an die Hauptaktivität und erklärt dem Nutzer, dass das Gerät die angegebenen Bytes nicht an das andere (verbundene) Gerät senden konnte.

Mit der Methode cancel() des Threads können Sie die Verbindung jederzeit beenden, indem Sie BluetoothSocket schließen. Rufen Sie diese Methode immer auf, wenn Sie die Bluetooth-Verbindung nicht mehr benötigen.

Eine Demonstration der Verwendung der Bluetooth APIs finden Sie in der Beispiel-App Bluetooth Chat auf GitHub.