while Schleife macht Probleme im neuen Thread

  • 22 Antworten
  • Letztes Antwortdatum
C

cederick

Neues Mitglied
0
Eine einfache und wahrscheinlich auch schnell beantwortete Frage, ich habe eine Runable die soweit auch funktioniert aber wenn ich die Thread.sleep(10000); Metode mit einer While- Schleife austausche passiert es ziemlich oft das auch der MainThread beansprucht wird und ich frage mich woran das liegt und natürlich warum es mit einer geschätzten Wahrscheinlichkeit von 30 % dann doch funktioniert.

der Thread wird so gestartet:

Code:
    public void surf_view_resume() {
        this_thread = new Thread(this);
        isrunning = true;
        this_thread.start();
    }

und die Runable sieht so aus:

Code:
    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        h.post(new Runnable() {
            @Override
            public void run() {
                calc.calc_resume();
                running_listener.onisrunning(isrunning);
            }
        });
        while (isrunning) {
            if (holder.getSurface().isValid() && !calc.isStartcalc()) {
                calc.setStartcalc(true);
                Canvas canvas = holder.lockCanvas();
                setcanvas(canvas);
                holder.unlockCanvasAndPost(canvas);
            }

        }
    }

und so sieht die Runable aus wenn ich eine While-Schleife verwende:

Code:
    @Override
    public void run() {
        int i = 0;
        while (i <= 1000000000) {
            i++;
        }
        h.post(new Runnable() {
            @Override
            public void run() {
                calc.calc_resume();
                running_listener.onisrunning(isrunning);
            }
        });
        while (isrunning) {
            if (holder.getSurface().isValid() && !calc.isStartcalc()) {
                calc.setStartcalc(true);
                Canvas canvas = holder.lockCanvas();
                setcanvas(canvas);
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }
 
What is a CPU hog

dein Thread verlangsamt offensichtlich alle wichtigeren Operationen aus dem MainThread der Activity
 
aber ich dachte die wären getrennt und warum wird das dann nicht wenigstens 50/50 aufgeteilt, also das beide Threads gleiche Priorität haben. Mir ist klar das sleep keinen Prozessor mehr braucht aber die while ist doch auch nur eine zahl die erhöht wird das kann doch nicht das Prinzip eines 2. Thread übern haufen werfen.
 
Was ist denn h? Ein Handler, klar, aber wie inistialisierst du den?
 
so:
Code:
h = new Handler();
        surf_view_resume();
Es ist auch im Code genauso hintereinander.
 
MAl ne Frage: Was amchst du mit dem Canvas eigentlich zwischen lock und unlock?
das habe ich nicht so verstanden: ich dachte da wird dein ladebildschirm gemalt aber es sieht aus als ob du einfach nur die referenz setzt.
 
Ich male auf die canvas in dieser Metode aber nochmal der Ladebildschirm wird noch nicht gezeichnet und er soll auch nicht in die Canvas gezeichnet werden sondern zuvor in einem anderen Layout und wenn die surf_view alle paints, views usw. initialisiert hat und vorbereitet hat dann soll erst die surf_view gezeichnet werden.
[DOUBLEPOST=1442845534,1442845192][/DOUBLEPOST]also :
MainThread = Ladebildschirm
2. Thread = laden
[DOUBLEPOST=1442846863][/DOUBLEPOST]Achso und das Zeichnen funktioniert auch ich habe eine fps Anzeige eingebaut und diese verändert sich, genause wie die Positionsangabe wenn ich tippe.
 
So wie du den Handler initialisierst ist das ein MainThread Handler, also keine 2 Threads. mit new Handler baust du einen Handler für den aktuellen Thread. Um einen eigenen Thread zu haben musst du einen HandlerThread initialisieren und den Looper dieses HandlerThreads in den Constructor des Handlers reingeben. So kannst du aus dem MainThread einen Handler für einen 2. Thread bauen.
 
Das soll ja auch ein MainThread Handler sein, ich muss vll sagen das ich mich mit Handlern noch nicht so beschäftigt habe aber wie ich das verstanden habe wird dadurch das ich den Handler im MainThread initialisiere, dieser Listener running_listener.onisrunning(isrunning); ein Callback auslösen wodurch ich mit dem anderen Thread(Mainthread) kommunizieren kann.

Der 2. Thread wird doch durch :
cederick schrieb:
public void surf_view_resume() {
this_thread = new Thread(this);
isrunning = true;
this_thread.start();
}
gestartet.
Also habe ich doch auch 2 Threads oder ?
 
Mainthread/UI Thread = Thread der Activity

Du erzeugst neben diesen MainThread der Activity einen einzigen Thread und einen Handler zum Thread. Der Code im Handler ( in der post() methode) wird nciht nebenläufig ausgeführt sondern auf dem Thread an den er gebunden ist.

Du bezeichnest deinen Thread als MAinThread aber unter Androidprogrammierern versteht man unter Mainthread eben den Toplevel Thread der den Code der Activity ausführt.

Processes and Threads | Android Developers <- unbedingt mal durchlesen

Handler | Android Developers <- auch das!
 
  • Danke
Reaktionen: cederick
Jaiel schrieb:
Du erzeugst neben diesen MainThread der Activity einen einzigen Thread und einen Handler zum Thread. Der Code im Handler ( in der post() methode) wird nciht nebenläufig ausgeführt sondern auf dem Thread an den er gebunden ist.
ist mir bewusst.
Jaiel schrieb:
Du bezeichnest deinen Thread als MAinThread aber unter Androidprogrammierern versteht man unter Mainthread eben den Toplevel Thread der den Code der Activity ausführt.
vll habe ich mich etwas unglücklich ausgedrückt aber hier:
cederick schrieb:
ein Callback auslösen wodurch ich mit dem anderen Thread(Mainthread) kommunizieren kann.
meinte ich natürlich das mein unbenannter Thread mit dem MainThread kommuniziert.

Jaiel schrieb:

den ersten Link habe ich mal überflogen und einiges wusste ich schon den Teil mit den Prozessen muss ich mir nochmal genauer durchlesen aber ich habe jetzt leider keine Zeit mehr dafür also lese ich mir das morgen Abend durch.

Ich finde es ja nett das ihr mich korrigieren wollt und mich auf den richtigen Pfad in Sachen richtiger Ausdrucksweise usw. bringen wollt. Doch glaube ich das wir etwas vom Thema abkommen.
 
Tja man kriegt heir Hilfe von allen Seite wenn nötig wird diese einem auch aufgezwungen ;)
Ohne deinen Code aus dem anderen Thread würde ich nciht wissen dass die initialisierung des Handler zum Beispiel im Konstruktor der Surfaceview implementiert ist und du damit auf der sicheren seite bist, dass der Handler den MAinthread anvisiert.

Zu deinem Topic: Irgendwo habe ich gelesen dass du nur auf dem Emulator getestet hast?! Kommen dieselben Probleme denn auch auf richtiger Hardware?
Ein Emulator ist immerhin ein Betriebssystem auf einem Betriebssystem also erwarte da bloß keine stabile Umgebung zu haben was solche Sachen angeht...
[DOUBLEPOST=1442874982,1442874639][/DOUBLEPOST]Achja: für deine Zwecke brauchst du nciht extra einen Handler anlegen es reicht ein einfacher(für dich als programmierer) runOnUiThread() dafür...

Hier die Android Implementierung:

Code:
public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

Du siehst der erledigt das schon von alleine mit einem Handler. Also nutze die vorhande Referenz des Handlers anstatt eine neue zu erstellen ;)
 
  • Danke
Reaktionen: cederick
Jaiel schrieb:
Tja man kriegt heir Hilfe von allen Seite wenn nötig wird diese einem auch aufgezwungen ;)
Finde ich gut :D.
Jaiel schrieb:
Ohne deinen Code aus dem anderen Thread würde ich nciht wissen dass die initialisierung des Handler zum Beispiel im Konstruktor der Surfaceview implementiert ist und du damit auf der sicheren seite bist, dass der Handler den MAinthread anvisiert.
Ist ja auch nicht notwendig zu wissen ich denke einfach immer wenn jmd. diese frage entdeckt wird er nicht antworten wenn er sich erstmal durch zwei Seiten kämpfen muss, würde ich ja auch nicht machen und ich habe auch schon getestet ob sich was ändert wenn ich den Handler rausnehme weil ich mit dem auch einfach noch am wenigsten gemacht hatte und demzufolge auch nicht wusste was da noch im Hintergrund passiert.

Jaiel schrieb:
Zu deinem Topic: Irgendwo habe ich gelesen dass du nur auf dem Emulator getestet hast?! Kommen dieselben Probleme denn auch auf richtiger Hardware?
Ein Emulator ist immerhin ein Betriebssystem auf einem Betriebssystem also erwarte da bloß keine stabile Umgebung zu haben was solche Sachen angeht...
Naja so ähnlich nur genau das Gegenteil :p, ich habe geschrieben das wenn ich mein Tablet anschließe der Explorer freezen kann und ich deshalb auch, Bridge nicht vw. kann und das mein PC schon min 4Jahre alt ist, weshalb der Emulator ewig lädt und manchmal das Laden auch nicht beendet.
Also es ist so das ich den Emulator scheue.


Jaiel schrieb:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
Das kenne ich noch nicht nach 2 Monaten Programmieren ^^, aber warum die Abfrage?
Wenn der MainThread nicht der Thread ist der darauf zugreift dann würde doch durch meine Whille(isrunning){} Schleife (die sich hier wohl in "action" befindet) den MainThread beschäftigen und die App freezen oder?
 
Ja wenn du eine unendliche loop hast wird es in jedem Fall die App freezen und das System würde nach einiger Zeit die App beenden.

Die Abfrage ist einfach nur da, falls diese Methode (unnötigerweise) vom Mainthread ausgerufen wird, dass das runnable dann einfach ausgeführt wird. Wenn es nicht vom Mainthread kommt dann wird es in die Schlange gestellt um es bei nächster Gelegenheit auf dem Mainthred auszuführen. Und auch dann wird deine loop die App freezen...
 
kk macht aber kaum einen Unterschied außer das es auf die queue (ich wüsste nicht wie man das auspricht) gesetzt wird und deine Methode direkt ausgeführt wird.
 
Doch bei dir schon: dein Handler hat einfach nur die Aufgabe eine bestimmte Anweisung auszuführen auf dem Mainthread. Er hält keine wichtigen Variablen oder so sondern wird einfach nur darauf beschränkt ein einziges Runnable abzufeuern.
Einfach um der Einfachheit Willen macht es wie ich schon weiter oben in einem Kommentar schrieb "in deinem Fall" mehr Sinn diese einfache Methode dafür zu benutzen. :)
Und es verringert den Speciher und Performance-Overhead beim Erstellen eines neuen Handler-Objektes noch dazu.
 
Zuletzt bearbeitet:
kk, ich weiß das ist etwas spät aber ich bin heute auf ein Problem gestoßen was mich wieder auf diesen abschnitt führte :
Processes and Threads | Android Developers
und da steht :
"Do not access the Android UI toolkit from outside the UI thread"
ganz unten, nur was ist damit gemeint darf ich in einem worker Thread keinerlei Views oder ViewGroups in die Hand nehmen oder darf ich sie wenigstens "getten" oder kann ich sogar einige Veränderung daran vornehmen wie skallieren. Denn ich skalliere u.a. in einem WorkerThread was auch funktioniert nur ich möchte nicht das es da später zu Fehlern kommt.
 
Es ist eigentlich relativ einfach.
Threads laufen meist nicht wirklich parallel, sondern sie werden relativ willkürlich nach einander aufgerufen. Und es ist dann immer nur ein Thread im einen Prozess aktiv (Gilt nicht für Multithreading).
Wenn du von eine anderen Thread eine Methode im UIThread aufrufst, blockierst du den Thread. Dh. solange kann keine andere Methode im UIThread ausgeführt werden. So reagiert das GUI nicht mehr auf User-Eingaben. Im schlimmsten Fall hängt sich die App auf.

Das andere Problem ist, das mehrere Threads auf die gleiche Variable zugreifen können. Im schlimmsten Fall greift der eine Thread auf eine Variable zu, die kurz vorher von einem anderen Thread geändert wurde (z.B auf null gesetzt).

Auch können Threads weiter ausgeführt werden, obwohl das Objekt, welches ihn gestartet hat, nicht mehr existiert.

Es gibt Möglichkeiten, dieses Verhalten zu unterbinden.
Rheinwerk Computing :: Java ist auch eine Insel - 12 Einführung in die nebenläufige Programmierung
 
cederick schrieb:
"Do not access the Android UI toolkit from outside the UI thread"
ganz unten, nur was ist damit gemeint darf ich in einem worker Thread keinerlei Views oder ViewGroups in die Hand nehmen oder darf ich sie wenigstens "getten" oder kann ich sogar einige Veränderung daran vornehmen wie skallieren.

Um mal speziell auf diese Frage zu antworten:

Natürlich darfst du referenzen verteilen wie du möchtest bloß einige Sachen dürfen nur auf dem UIThread passieren. Das ist ein Design Pattern das Android da benutzt um Sicherheit zu gewähren damit die Daten eienr View nciht in einem inkonsistenten Zustand sind.

Für manche Sachen hat sich Android einfach gedacht dass diese in einer bestimmten Reihenfolge zu bestimmten Zeiten ablaufen müssen. Und wirft somit einfach Exceptions die du nciht abfangen solltest oder kannst da bin ich mir nicht sicher damit du einfach das System nicht kaputt machst.

Zum Beispiel kannst du einen Adapter nciht aus einem anderen Thread dazu auffordern seine Daten zu aktualisieren glaube ich mich zu errinnern
 
Ich greife mal Jaiel's Gedanken auf.
Android läuft auf ein Linux. In Linux läuft jedes Programm (App) in mindesten einen Prozess. Eine normale App (Prozess) braucht ein Thread, der die Interaktion mit den Benutzer organisiert (UI).

D.h. er wartet auf Eingaben (Touch, Keyboard) und organisiert die Ausgabe. Je mehr Aufgaben er zusätzlich erledigen muss (Berechnungen, Netzwerkkommunikation usw,), desto weniger Zeit hat er für seine Hauptaufgabe. Im schlimmsten Fall ist der UIThread mit anderen Aufgaben beschäftigt, das er zu nichts anderes mehr kommt. Das nennt man dann ANR. Keeping Your App Responsive | Android Developers

Also lagert man Aufgaben in andere Thread's aus. Und wie Jaiel anmerkte, weiß der eine Thread nicht, was der andere macht. Die Daten könne inkonsistent sein. Oder aber der UIThread ist gerade mit anderen Sachen beschäftigt (s.o).

Deshalb gibt es mehrere Schnittstelle für die Kommunikation mit den UIThread (z.B runOnUiThread(), Handler, Broadcast usw.).

Jaiel schrieb:
Zum Beispiel kannst du einen Adapter nciht aus einem anderen Thread dazu auffordern seine Daten zu aktualisieren glaube ich mich zu errinnern

Natürlich geht das, du muss nur die passenden Schnittstellen benutzen. ;)
 
Zurück
Oben Unten