Объединение сообщений inputStream.read

Я использую Android Bluetooth Chat образец кода для чата (отправка команд + получение ответов) с устройством Bluetooth. Он работает нормально, когда я отправляю команду и получаю ответ от устройства, который передается обработчику сообщений. Проблема, с которой я сталкиваюсь, заключается в том, что ответ разрезается на части.

Пример:

Я отправляю строку "{Lights:ON}\n", и моя активность правильно отображает Me: {Lights:ON}. Индикаторы устройства включаются, и он возвращает ответ "{FLash_Lights:ON}\n". Однако моя активность отображает DeviceName: {Fla, новую строку, DeviceName: sh_Lights:ON} (или некоторые варианты и т. Д.).

Теперь я новичок в многопоточности и bluetooth в целом, но я проследил проблему до класса подключенного потока (в bluetoothchatservice), в частности, public void run() для прослушивания входящих байтов.

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

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = mmInStream.read(buffer);

                    // Send the obtained bytes to the UI Activity
                    mHandler.obtainMessage(BluetoothActivity.MESSAGE_READ, bytes, -1, buffer)
                            .sendToTarget();
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    // Start the service over to restart listening mode
                    BluetoothThreading.this.start();
                    break;
                }
            }
        }

Я понимаю, что это было сделано для прослушивания любых входящих байтов (как служба чата). Однако я точно знаю, что я пишу на устройство, и я знаю ответ, который я должен получить, что я хотел бы сделать, так это связать этот ответ перед отправкой обратно в mHandler.

Любая помощь с этим была бы потрясающей! Спасибо!

Примечание. Я знаю, что использование этого примера в качестве способа отправки команды на устройство и получения ответа немного излишне (тем более, что я точно знаю, что отправляю, и что мне нужно получить сразу после этого). ). Было бы здорово, если бы вам указали на любой известный вам упрощенный образец. В конце концов, мне просто нужно выполнить поиск, подключиться к устройству, нажать кнопку, чтобы отправить байт [] на устройство, получить ответ байта [], распечатать + сохранить его.


person user2634703    schedule 03.06.2014    source источник
comment
bytes=mmStream.read(buffer) не читает строки. Он просто читает несколько байтов. Проверьте свои переменные байты для этого. Поэтому вам нужно сделать цикл для заполнения буфера, пока \n не будет прочитан. Или, если вы можете использовать mmStream.readLine(), используйте это.   -  person greenapps    schedule 03.06.2014


Ответы (1)


'read ()' блокирует вызов и возвращается, когда через Bluetooth получено несколько байтов. Количество «несколько» не фиксировано, и именно поэтому входящий ответ кажется разбитым на части. Поэтому, чтобы получить полный ответ, все эти части должны быть соединены вместе.

Если поток ответа завершается определенным символом, то следующая логика кода может накапливать байты, поступающие до завершающего символа. И как только завершающий символ обнаружен, накопленный ответ отправляется в основную активность. (Обратите внимание, что в приведенном ниже фрагменте кода используется завершающий символ 0x0a).

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

// Keep listening to the InputStream while connected
while (true) {
    try {
        // Read from the InputStream
        bytes = mmInStream.read(buffer);

        btInStream.write(Arrays.copyOf(buffer, bytes) );

        if (buffer[bytes - 1] == 0x0a){
            mHandler.obtainMessage(MainActivity.MESSAGE_READ, btInStream.size(), 0,btInStream.toByteArray());
            .sendToTarget();
            btInStream.reset();
        }
    } catch (IOException e) {
        Log.e(TAG, "disconnected", e);
        connectionLost();
        // Start the service over to restart listening mode
        BluetoothThreading.this.start();
        break;
    }
}
}

Также обратите внимание, что код не тестируется, но предлагается как один из подходов к решению проблемы, упомянутой в вопросе. Может быть, это потребует исправления в нескольких местах. Прошу протестировать и сообщить результаты.

person SunGa    schedule 04.06.2014
comment
Спасибо! Так что все работало, кроме оператора if. Я помещаю Log.d(btInputStream, btInStream.toString()); и он печатает правильную строку. Последним символом в строке должен быть }, который в шестнадцатеричном формате равен 7d, я пробовал 0x7d, 7d, пробовал его в десятичном виде и пробовал там целую кучу других символов, но оператор if никогда не срабатывает. - person user2634703; 04.06.2014
comment
Пожалуйста, попробуйте преобразовать обе стороны аргументов в операторе if в короткое целое. например if ((short)buffer[bytes - 1] == (short)0x0a){...} - person SunGa; 04.06.2014
comment
Приведены к коротким с обеих сторон. Перепробовал кучу шестнадцатеричных и десятичных переменных, и все равно не повезло. - person user2634703; 04.06.2014
comment
Две области для поиска: 1. заменить блок if{} следующим образом: if ((short)buffer[bytes - 1] == (short)0x0a){ byte[] arrcopy = new byte[btInStream.size()]; arrcopy = btInStream.toByteArray(); mHandler.obtainMessage(MainActivity.MESSAGE_READ, arrcopy.length,0,arrcopy) .sendToTarget(); btInStream.reset(); } 2. Третий аргумент в mHandler.obtainMessage() в этом коде равен 0, тогда как в опубликованном вами вопросе он равен -1. Проверьте, что требуется, и используйте правильный. - person SunGa; 04.06.2014