Android Bluetooth Communication: Data Loss and Disordering in Data Transmission Part of Android Bluetooth obtainMessage

Keywords: Android Google Mobile

According to the Bluetooth communication program written by google demo, when receiving Bluetooth information, it is found that some of the received data are lost and disordered.
Viewing the data transmission result of Bluetooth module on the computer serial port is normal.
But when using Bluetooth to transmit data, the problem of data loss will arise on the upper computer (Android mobile client), and the data loss is particularly serious:

Since the output of the serial port is correct, it proves that there is no problem with the MCU itself.
Then look at Bluetooth module: Bluetooth module hc-05, supporting Bluetooth v2.0, transmission rate is about 1.8M/s-2.1M/s, so there is no pressure to transfer that point of data in a second. So what's the problem? There's one last questionable goal: the PC.

The code for Bluetooth communication on the PC is google's official demo, so it was not suspected at first.
Then the data received in demo is written as follows:

public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            // Continue listening to InputStream and connect at the same time
            while (true) {
                try {
                    // Read input stream
                    bytes = mmInStream.read(buffer);

                    // User Interface for Sending Obtained Bytes
                    mHandler.obtainMessage(RetimeFragment.MESSAGE_READ, bytes, -1, buffer)
                            .sendToTarget();
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    break;
                }
            }
        }

Then handler's processing is written as follows:

case MESSAGE_READ://3Read data
                    byte[] readBuf = (byte[]) msg.obj;

                    String readMessage = new String(readBuf, 0, msg.arg1);
                    mInputEditText.getText().append(readMessage);
                    fmsg += readMessage;

Then some data is lost in the UI thread. ..

There are two ways of handler messaging, one is the obtainMessage() method given in the code above, and the other is the sendMessage() method.

The main difference between the two methods is that obtainMessage() takes out the Message object from the global object pool, while sendMessage() is a new object, so obtainMessage() is more efficient.

Android also recommends that we get Message objects through Message. get () or Handler.obtainMessage(). Because the obtaintain method does not necessarily create a new instance directly, but first looks at the message pool to see if there is a Message instance available, and then takes it out and returns it directly. Conversely, if no Message instance is available in the message pool, a new Message object is created based on the given parameter. By analyzing the source code, we can see that the Android system instantiates 10 Message objects in the message pool by default.

Therefore, it is possible to take a Message object from the global object pool and override the object in the message queue sent to the UI thread, resulting in data loss. So instead of using sendMessage(), new comes out with a new Message object to solve this problem.

Use sendMessage():

case MESSAGE_READ:
                    Bundle data = msg.getData();
                    String readMessage = data.getString("BTdata");
                    fmsg += readMessage;

Corresponding run()

 public void run() {

            byte[] buffer = new byte[1024];
            int bytes;
            String readMessage;
            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    int availableBytes = mmInStream.available();
                    if (availableBytes > 0) {
                        bytes = mmInStream.read(buffer);
                        Message msg = new Message();
                        Bundle data = new Bundle();
                        readMessage = new String(buffer,0,bytes);
                        data.putString("BTdata",readMessage);
                        msg.what = RetimeFragment.MESSAGE_READ;
                        msg.setData(data);
                        mHandler.sendMessage(msg);
                    }

                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    break;
                }
            }
        }

The result is correct, but it affects the efficiency problem.

Posted by Aureole on Wed, 17 Apr 2019 01:57:33 -0700