Отправка битов по Bluetooth в Android studio

227
15 апреля 2022, 01:20

я только начал изучать Java и среду разработки Android studio. Это мой первый вопрос, так что не судите строго. К делу. Я пытаюсь подружить приложение, созданное в Android studio и блютуз модуль HC-06. Код приложения

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/buOff"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="314dp"
        android:layout_marginEnd="70dp"
        android:onClick="Off"
        android:text="Выкл"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/buOn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="72dp"
        android:layout_marginTop="314dp"
        android:onClick="On"
        android:text="Вкл"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="168dp"
        android:layout_marginTop="402dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

package com.example.myapplication3;
import androidx.appcompat.app.AppCompatActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.icu.text.RelativeDateTimeFormatter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {
    private InputStream mmInStream = null;
    //Сокет, с помощью которого мы будем отправлять данные на Arduino
    BluetoothSocket clientSocket;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    //    public void On(View view){
//        try {
//            OutputStream outStream = clientSocket.getOutputStream();
//            outStream.write(1);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
//
//    public void Off(View view){
//        try {
//            OutputStream outStream = clientSocket.getOutputStream();
//            outStream.write(0);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
    @Override
    protected void onStart() {
        super.onStart();
        byte[] buffer=new byte[1024];// буферный массив
        int bytes;// bytes returned from read()
        while (true){
            try {
                bytes=mmInStream.read(buffer);

            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }
    public void run(){
        byte[] buffer=new byte[1024];// буферный массив
        int bytes;// bytes returned from read()
        while (true){
            try {
            bytes=mmInStream.read(buffer);

            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }
   public void init(){
        String enableBT = BluetoothAdapter.ACTION_REQUEST_ENABLE;
        startActivityForResult(new Intent(enableBT), 0);
        BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
       InputStream tmpIn=null;
       OutputStream tmpOut=null;
        try{
            //Устройство с данным адресом - наш Bluetooth Bee
            //Адрес опредеяется следующим образом: установите соединение
            //между ПК и модулем (пин: 1234), а затем посмотрите в настройках
            //соединения адрес модуля. Скорее всего он будет аналогичным.
            BluetoothDevice device = bluetooth.getRemoteDevice("98:D3:31:FB:B3:10");
            //Инициируем соединение с устройством
            Method m = device.getClass().getMethod(
                    "createRfcommSocket", new Class[] {int.class});
            clientSocket = (BluetoothSocket) m.invoke(device, 1);
            clientSocket.connect();
            //В случае появления любых ошибок, выводим в лог сообщение
        } catch (IOException e) {
            Log.d("BLUETOOTH", e.getMessage());
        } catch (SecurityException e) {
            Log.d("BLUETOOTH", e.getMessage());
        } catch (NoSuchMethodException e) {
            Log.d("BLUETOOTH", e.getMessage());
        } catch (IllegalArgumentException e) {
            Log.d("BLUETOOTH", e.getMessage());
        } catch (IllegalAccessException e) {
            Log.d("BLUETOOTH", e.getMessage());
        } catch (InvocationTargetException e) {
            Log.d("BLUETOOTH", e.getMessage());
        }
       try{
           tmpIn= clientSocket.getInputStream();
//           tmpOut= clientSocket.getOutputStream();
       } catch(IOException e){}
       mmInStream= tmpIn;
//       mmOutStream= tmpOut;
       Toast.makeText(getApplicationContext(), "CONNECTED", Toast.LENGTH_LONG).show();
//       run();
   }
        //Выводим сообщение об успешном подключении
    }

Что я получаю сейчас. При запуске приложения через Debug, я вижу, что по блютузу информация до меня доходит Но при этом приложение висит на "белом экране". При закомментировании бесконечного цикла, приложение "оживает" и выводит компоненты на экран. В чем может быть проблема ?

Знаю, что среди людей, которые ответят будут гуру своего дела, заодно был бы очень рад критике.

Answer 1

Была добавлена функция mainProcessing() в OnStart() Код

 @Override
    protected void onStart() {
        super.onStart();
        mainProcessing();
    }

Далее, добавил отдельный поток следующим кодом и засунул в него ту часть кода, которая отвечает за получение данных в реальном времени

    // Этот метод вызывается из главного потока GUI.
    private void mainProcessing() {
        // Здесь трудоемкие задачи переносятся в дочерний поток.
        Thread thread = new Thread(null, doBackgroundThreadProcessing,
                "Background");
        thread.start();
    }
    // Объект Runnable, который запускает метод для выполнения задач
// в фоновом режиме.
    private Runnable doBackgroundThreadProcessing = new Runnable() {
        public void run() {
            backgroundThreadProcessing();
        }
    };
    // Метод, который выполняет какие-то действия в фоновом режиме.
    private void backgroundThreadProcessing() {
        final InputStream mmInStream;
        InputStream tmpIn = null;
        TextView text = (TextView) findViewById(R.id.textView);
        try {
            tmpIn = clientSocket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mmInStream = tmpIn;
        byte[] bytes = new byte[38];
        int iterator = 0;
        while (true) {
            try {
                int bytesAvailable = mmInStream.available();
                if (bytesAvailable > 0) {
                    byte[] curBuf = new byte[bytesAvailable];
                    mmInStream.read(curBuf);
                    for (byte b : curBuf) {
                        if (b == (byte) 0xAA && iterator == 38) {
                            iterator = 0;
                            bytes[iterator] = b;
                        } else {
                            bytes[iterator] = b;
                            text.setText(b);
                        }
                        iterator++;
                    }
                }
            } catch (IOException ex) {
                break;
            }
        }
    }
Answer 2

Ребята, добавляю еще 1 ответ, сейчас поясню почему. Ответ выше - подходит в случае, если вы Не собираетесь изменять какие-либо элементы приложения (Текстовые поля, названия кнопок, цвет бэкграунда). Если же вам нужно изменять элементы приложения, вам подойдет это решение. Внимание, из-за своей неграмотности и незнания терминов, я могу накосячить с описанием, но думаю суть вы уловите.

@Override
    protected void onStart() {
        super.onStart();
        MYAsync myAsync=new MYAsync();
            myAsync.execute();
    }

Создаю новый объект класса MYAsync Вызываю функцию doInBackground(), описанную выше с помощью метода execute(); Описание, что я делал ниже - смотри в конце кода.

    class MYAsync extends AsyncTask<Void, String, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
                final InputStream mmInStream;
                InputStream tmpIn = null;
                try {
                    tmpIn = clientSocket.getInputStream();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                mmInStream = tmpIn;
                byte[] buffer = new byte[1024];
                int bytes ;// bytes returned from read()
            while (true){
                buffer= new byte[1];
                try {
                    bytes= mmInStream.read(buffer);
                } catch (IOException e) {
                    e.printStackTrace();
                }
               String str = buffer.toString();
                publishProgress(str);
            }
        }
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            TextView text = (TextView) findViewById(R.id.textView1);
            text.setText(values[0]);
        }
    }

Смотри, Есть такая вещь - UI (юзер интерфейс) - по факту это и есть все те кнопки, текстовые поля итд, которые ты хочешь использовать в коде. Я использовал 2 метода класса doInBackground() и onProgressUpdate(). Зачем? Все дело в том, что функция doInBackground() не имеет доступ к тому самому UI и не может менять допустим текст в текстовом поле, но зато она используется для другого - для долгих/сложных вычислений, но вот onProgressUpdate() - может изменять UI. Спросишь меня- как же передать значение в onProgressUpdate() из onProgressUpdate(). Вот так. publishProgress(str); Лично я передаю переменную str, ее тип я указал на самом верху, при описывании класса class MYAsync extends AsyncTask<Void, String, Void>. Дальше , я принимаю переменную protected void onProgressUpdate(String... values). values и есть та самая str. И изменяю текст TextView вставляя в него values[0]. Поскольку в моем случае str - это стринг массив. Описал, как было бы понятно мне (очень подробно).

READ ALSO
Как прочитать JSON объект в Java

Как прочитать JSON объект в Java

Я пытаюсь прочитать JSON объект в Java (только начинаю с JSON)

240
Как создать POJO обьект из YAML файла использую Spring Boot?

Как создать POJO обьект из YAML файла использую Spring Boot?

По идее все просто если файл yaml называется applicationyaml тогда обьект (POJO) со следующими аннотациями

169
Socket-server java on apache-tomcat

Socket-server java on apache-tomcat

Интересует возможность развёртывания Сокет-сервера java на apache-tomcat

216
Разделение строки по 3 символа

Разделение строки по 3 символа

В данной строчке кода (в теории) должен объявляться массив, в который присваивается огромное предложение без пробелов, разделённое по три...

311