getInputStream() blockiert UIThread

  • Antworten:6
  • Bentwortet
Gelöschter Account
  • Forum-Beiträge: 3

05.11.2019, 08:01:46 via Website

Hallo,

Hintergrundinfos: ich versuche momentan eine App zum konfigurieren von Seriellen Interfaces zu erstellen. Über eine Bluetooth-Connection verbindet sich das Smartphone mit einem Bluetooth-Dongle zum Endgerät und kann dort über den InputStream die Daten abrufen oder per OutputStream einen Befehle absenden.

Das ganze funktioniert soweit ohne Probleme. Nachdem die Verbindung mit dem Bluetooth-Dongle hergestellt wurde und ein Button zum Starten des InputStreams gedrückt wurde, wird das UI solange blockiert, bis erste Daten von der seriellen Schnittstelle gesendet wurden. Dieses Problem möchte ich aber umgehen, sodass ich auch ohne das vom Gerät gerade Informationen gesendet werden, Befehle von mir gesendet bzw. die Verbindung getrennt werden kann. Dies kann ich aber nicht solange der InputStream wartet, bis die ersten Zeichen erscheinen.
Ich habe schon mittels Threads versucht die ganze Aktion in den Hintergrund zu legen, leider jedoch wird nach dem Aufruf weiterhin der UIThread blockiert - warum auch immer.
Beim verwenden des Threads in der onCreate Methode wird natürlich die Activity erst aufgebaut, sobald die ersten Zeichen vom InputStream empfangen wurden.

Der Thread wird danach automatisiert in gewissen Takt aufgerufen um die gesendeten Informationen vom Endgerät zu empfangen.

Nun meine Frage: Wie kann ich es erreichen, das der InputStream meinen UIThread nicht blockiert, auch wenn er vom Endgerät noch keine Informationen erhält?

public class TerminalSession extends AppCompatActivity {

// Variablen
private String readMessage;
private Thread reading_thread;
private Handler reading_handler = new Handler();

// Variablen für Widgets
Button start_Reading, Disconnect, send_Command;
static TextView cli = null;
EditText command;

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

    // Variablen an Widgets binden
    start_Reading = (Button) findViewById(R.id.start_Reading);
    Disconnect = (Button) findViewById(R.id.Disconnect);
    send_Command = (Button) findViewById(R.id.send_Command);
    cli = (TextView) findViewById(R.id.cli);
    cli.setMovementMethod(new ScrollingMovementMethod());
    command = (EditText)findViewById(R.id.command);


    // OnClickListener auf Buttons setzen

    start_Reading.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            logging("Starte Lesevorgang-Thread");
            startReadingThreat();
        }
    });

    Disconnect.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            logging("Disconnect");
            //reading_handler.removeCallbacks(null);
            disconnect();
        }
    });

    send_Command.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            logging("Send Command");
            sendCommand();
        }
    });
    //startReadingThreat();
}  // Ende der OnCreate-Funktion   

// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Reading-Threat

private void startReadingThreat()
{
    reading_thread = new Thread()
    {
        @Override
        public void run()
        {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

            try {

                InputStream inputStream = myBTSocket.getInputStream();

                byte[] buffer = new byte[256];
                int bytes;

                try {
                    bytes = inputStream.read(buffer);                                               // Lese die Bytes vom input buffer
                    readMessage = new String(buffer, 0, bytes);
                    logging(readMessage + "");
                } catch (IOException e) {
                    logging("Lesevorang nicht möglich");
                }
            } catch (IOException e) {
                logging("InputStream nicht lesbar");
            }
        }
    };

    reading_handler.post(new Runnable() {
        @Override
        public void run() {
            reading_thread.run();
            cli.append(readMessage);
            logging("h.postDelayed - run: " + readMessage);
            reading_handler.postDelayed(this,1000);
        }
    });


    reading_thread.start();
    //reading_handler.removeCallbacksAndMessages(this);
}
private void logging(String message) {
    Log.d(TAG, "Log-Entry Nr. " + (log_counter++) + ": " + message);
}
Kommentieren
Beste Antwort
Rafael K.
  • Forum-Beiträge: 2.359

09.11.2019, 15:54:35 via Website

Also Grundsätzlich macht man sowas unter Android mit einem AsyncTask.
Selbst Threads zu erstellen ist unter Android problematisch und wird nicht empfohlen, weil man die ganzen Mechanismen umgeht, die dem Betriebssystem erlauben die Performance zu optimieren.

Zu deinem Problem:
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

Man starten einen Thread NICHT mit run(), das ist nur die Interface Methode, die man für seine Logik implementiert und die von der Thread Klasse dann intern aufgerufen wird.
Um den Thread anzustoßen, verwendet man start().

Hilfreich?
swa00
Kommentieren
swa00
  • Forum-Beiträge: 3.704

05.11.2019, 08:22:41 via Website

Hallo Floid .

der UI Thread muss grundsätzlich separat angesteuert werden , wenn du aus einem Thread heraus Elemente ansprechen willst : runOnUiThread

https://developer.android.com/reference/android/app/Activity#runOnUiThread(java.lang.Runnable)

— geändert am 05.11.2019, 09:06:19

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
JokelPascal P.
Kommentieren
Gelöschter Account
  • Forum-Beiträge: 3

09.11.2019, 15:31:29 via Website

Hallo,
vielen Dank für deine Antwort.
Ich habe viele mit runOnUiThread rumprobiert, aber leider komme ich zu keinem anderen Ergebnis. Das UI ist solange blockiert, bis die ersten Zeichen ankommen.

Wie muss ich meinen bisherigen Code anpassen?

Hilfreich?
Kommentieren
Beste Antwort
Rafael K.
  • Forum-Beiträge: 2.359

09.11.2019, 15:54:35 via Website

Also Grundsätzlich macht man sowas unter Android mit einem AsyncTask.
Selbst Threads zu erstellen ist unter Android problematisch und wird nicht empfohlen, weil man die ganzen Mechanismen umgeht, die dem Betriebssystem erlauben die Performance zu optimieren.

Zu deinem Problem:
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

Man starten einen Thread NICHT mit run(), das ist nur die Interface Methode, die man für seine Logik implementiert und die von der Thread Klasse dann intern aufgerufen wird.
Um den Thread anzustoßen, verwendet man start().

Hilfreich?
swa00
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

09.11.2019, 16:45:41 via Website

Hallo dein Problem ist dein Handler . Wie dir schon gesagt wurde darf die run Methode nie von Außen aufgerufen werden. Denn dann läuft sie im UI was du nicht willst.
Lösche deinen Handler Komplet und benutze RunOnUiThread wie schon gesagt wurde.
Versuche es mal in etwa so

private void startReadingThreat()

{
reading_thread = new Thread()
{
@Override
public void run()
{
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

        try {

            InputStream inputStream = myBTSocket.getInputStream();

            byte[] buffer = new byte[256];
            int bytes;

            try {
                bytes = inputStream.read(buffer);                                               // Lese die Bytes vom input buffer
                readMessage = new String(buffer, 0, bytes);
                logging(readMessage + "");

                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                         cli.append(readMessage);
                         logging("h.postDelayed - run: " + readMessage);  
                    }
                });


            } catch (IOException e) {
                logging("Lesevorang nicht möglich");
            }
        } catch (IOException e) {
            logging("InputStream nicht lesbar");
        }
    }
};


reading_thread.start();
//reading_handler.removeCallbacksAndMessages(this);

}

Hilfreich?
swa00
Kommentieren
Gelöschter Account
  • Forum-Beiträge: 3

15.11.2019, 15:57:16 via Website

Problem mithilfe von Async gelöst, viel zu kompliziert gedacht. Danke für die Hilfe.
Kann ich den Thread als gelöst makieren oder löschen?

Hilfreich?
Kommentieren
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

15.11.2019, 18:45:38 via App

Da du eine beste Antwort festgelegt hast, ist der schon automatisch als beantwortet markiert

LG Pascal //It's not a bug, it's a feature. :) ;)

Hilfreich?
Gelöschter Account
Kommentieren