最近自己做一个计步器,需要从从机(arduino uno + mpu6050 + hc-05)接收数据,每一秒钟接收20组长度为20字节左右的数据,在串口上观察数据输出结果正常,如图1:



android 显示蓝牙传输速度 安卓蓝牙传输很慢_数据丢失

但是当利用蓝牙传数据的时候,上位机端(安卓手机客户端)就会出现数据丢失的问题,如图:

android 显示蓝牙传输速度 安卓蓝牙传输很慢_数据丢失_02

可以发现,这个数据丢的特别严重,既然串口上面输出的结果是正确的,那么证明单片机本身没有任何问题。我把目光转移到了蓝牙模块上。蓝牙模块hc-05,支持蓝牙v2.0,传输速率大约在1.8M/s---2.1M/s,所以一秒传我那最多400字节的数据没有任何压力(这个排除法我可是做了整整2天啊。。。还和网友通宵交流。。。没办法遇到难题还能怎么半呢,还是得自己想法子解决,不要想着别人可以帮你解决)。那么问题出在哪里呢?还有最后一个可以怀疑得目标,上位机!

上位机上得蓝牙代码用得是google官方demo,然后demo里面接收数据是这么写的:


<span style="font-size:18px;">public void run() {//接收数据的线程

            byte[] buffer = new byte[1024];
            int bytes;
            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    bytes = mmInStream.read(buffer);
                    mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget();

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



然后handler的处理是这么写的:

case MESSAGE_READ://3读取数据

                  byte[] readBuf = (byte[]) msg.obj;
                  recieveStr = new String(readBuf, 0, msg.arg1);//得到数据字符串
                  Log.e("Length",String.valueOf(recieveStr.length()) + "  " + recieveStr);
<span style="white-space:pre">		</span>  break;



然后结果就有了上面的那一幕,数据丢了!

我苦思冥想,觉得官方的demo毕竟是google神牛写的啊,99%都没啥问题的呀(1%留给自己来质疑),然后我就一行代码一行代码的排除,然后就发现handler消息传递有两种方法,一种就是上面代码里面给出来的obtainMessage()方法,另外一种就是sendMessage()方法,然后这两种方法有什么区别呢,大家可以先看看这个解释详细的:传送门1,传送门2

其实就是一个new与不new,导致的效率不同的区别,obtainMessage()因为是直接从message global pools里面取出的一个新的message实例,所以在快传大量数据的过程中,MessageQueue大小有限,如果消息处理不及时,而又有新的数据写入,有可能造成message被覆盖,也就出现了上面的数据丢失现象。虽然android推荐使用obtainMessage(),有其利但是也有其弊。

于是我就尝试用sendMessage()来解决问题:

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 = MainActivity.MESSAGE_READ;
                        msg.setData(data);
                        mHandler.sendMessage(msg);
                    }


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



handler处理:

case MESSAGE_READ://3读取数据

            
                    Bundle data = msg.getData();
                    recieveStr = data.getString("BTdata");
                   Log.e("Length",String.valueOf(recieveStr.length()) + "  " + recieveStr);

                    writeFile(recieveStr);//把收到的数据写到文件里面
                    break;



看看运行结果:

android 显示蓝牙传输速度 安卓蓝牙传输很慢_上位机_03

非常好,解决了数据丢失的问题。虽然这样做牺牲了部分效率,但是相比丢数据这种危险的事情,这是非常非常值得的。

上文如果有错误的地方,请各位指正!