Anfängerproblem?

  • Antworten:12
  • Bentwortet
Gelöschter Account
  • Forum-Beiträge: 602

19.11.2009, 16:12:02 via Website

Hallo zusammen,

versuche mich grade ein bischen in Android-Entwicklung einzuarbeiten, und scheitere momentan an einem einfachen Problem.
Zum Anfang hab ich einfach mal den Uptime-Wert ausgelesen und in einen String verarbeitet (á la "Uptime: 2 Tage, 1 Stunde, 3 Minuten, 0 Sekunden"). Nun habe ich ein Menü hinzugefügt, dass einmal einen Refresh-Knopf hat (manuelles Updates der Anzeige) und einen Trigger AutoUpdate-Knopf (für automatisches Update des Wertes einmal in der Sekunde). Das AutoUpdate ist in einen Thread verfrachtet. So sieht's also aus:

1public void setAutoUpdate() {
2 if(autoUpdate) {
3 autoUpdate = false;
4 runAutoUpdateThread.stop();
5 }
6 else {
7 autoUpdate = true;
8 runAutoUpdateThread = new AutoUpdateThread();
9 runAutoUpdateThread.run();
10 }
11 }
12
13 class AutoUpdateThread extends Thread {
14 public void run() {
15 do {
16 try {
17 refreshSystemInfo();
18 Thread.sleep(1000);
19 }
20 catch(InterruptedException e) {}
21 }while(true);
22 }
23 }

setAutoUpdate() wird aufgerufen, wenn der entsprechende Knopf gedrückt wird. refreshSystemInfo() berechnet und schreibt einfach die Werte neu auf den Bildschirm.
Was passiert: Beim Drücken des Knopfes hängt sich das Prog ohne Meldung auf, friert also einfach ein. Nach einer Weile folgt dann "Aktivität TestApplication .. bla .. reagiert nicht".
Der Eclipse-Debug hat leider nix gebracht, denn dann bekomm ich die "reagiert nichtmehr"-Meldung nicht mehr...

Antworten
Markus Gu
  • Forum-Beiträge: 2.644

19.11.2009, 16:30:23 via Website

threads starten man nicht mittles run()

sondern mittels start()

du musst nur die run() methode überschreiben, aber die Thread.start() macht daraus einen wirklichen thread

swordiApps Blog - Website

Antworten
Gelöschter Account
  • Forum-Beiträge: 602

19.11.2009, 16:44:20 via Website

start() hatte ich probiert (da ich das auch kannte und erwartet hatte), führt aber zu "TestApplication wurde unerwartet beendet", sobald ich den Button drücke. :/
run() wurde im Tooltip damit bezeichnet, dass es die run-Methode direkt aufruft, daher hatte ich das einfach mal probiert...

Antworten
Gelöschter Account
  • Forum-Beiträge: 22

19.11.2009, 17:13:47 via Website

Kleine Anmerkung dazu: Bitte rufe nicht Thread.stop() auf. Die Methode ist deprecated, da der Thread in einem unsauberen Zustand beendet wird. Du kannst zum Beispiel in der run()-Methode statt while(true) ein while(threadRunning) schreiben und dann threadRunning auf false setzen, wenn der Thread beendet werden soll.

Antworten
Markus Gu
  • Forum-Beiträge: 2.644

19.11.2009, 17:36:43 via Website

du kannst schon direkt run aufrufen, jedoch wird dann kein thread erzeugt. ist wie eine normale methode dann

swordiApps Blog - Website

Antworten
Gelöschter Account
  • Forum-Beiträge: 602

19.11.2009, 18:37:15 via Website

Das stop() war auch nur, um er erstmal laufen zu haben (es ist ja schon vorher gescheitert).
Es war ursprünglich so gedacht, alles in run() in eine while(!interrupted) zu schieben, aber über while(autoUpdate) (was ich sowieso benutzt habe), macht es natürlich noch einfacher.
Das Problem liegt aber wohl immernoch beim Starten. So wie es momentan ist, tut der Thread garnichts.
Und ich glaube, ich weiß auch warum. Hier...
http://www.helloandroid.com/node/243
... findet man den Hinweis, dass ein Thread kein UI-Element update kann. In meinem Fall wollte ich ja ein TextView über setText updaten. Scheint wohl nicht zu gehen. Also mal schauen, wie ich das anders lösen kann (vermute mal über einen String-Verweis)...

Danke euch!

Antworten
goto android
  • Forum-Beiträge: 138

19.11.2009, 22:46:24 via Website

Die Lösung ist ein simpler Handler diesen rufst du auf, wenn du aus deinem zweiten Thread auf die GUI zugreifen willst.
Du implementierst die Methode handleMessage(Message msg), in dieser kannst du auf die GUI zugreifen, aufrufen tust du sie dann aus deinem Thread mithilfe von sendEmptyMessage(int value) oder einer der anderen Varianten, für deinen Fall sollte die aber reichen:

1class AutoUpdateThread extends Thread {
2 public boolean interrupt;
3 android.os.Handler handler = new android.os.Handler() {
4 @Override
5 public void handleMessage(Message msg) {
6 refreshSystemInfo();
7 }
8 };
9 public void run() {
10 while(!interrupt) {
11 try {
12 handler.sendEmptyMessage(0);
13 Thread.sleep(1000);
14 }
15 catch(InterruptedException e) {
16 }
17 }
18 }
19}
Habs jetzt nicht getestet, denke aber das sollte so klappen. :D

Edit: Das mit dem einrücken will wohl nicht so ganz funktionieren. :/

— geändert am 20.11.2009, 16:46:48

Antworten
Gelöschter Account
  • Forum-Beiträge: 602

20.11.2009, 13:30:58 via Website

Nein, funktionieren tut das auch nicht... :(
(Das @Override mochte Eclipse nicht, stattdessen wollte er ein @SuppressWarnings("unused") dort haben - was auch immer das tut..)
Langsam glaube ich, da ist was anderes faul . . . :/
Aber DANKE für eure bemühungen!

— geändert am 20.11.2009, 13:31:11

Antworten
Markus Gu
  • Forum-Beiträge: 2.644

20.11.2009, 13:32:38 via Website

da ist eher was anderes faul
hast du zufällig mac? bei einem bekannt am mac wollte er diese @override auch nicht haben

das mit dem handler muss aber so funktionieren.

swordiApps Blog - Website

Antworten
Gelöschter Account
  • Forum-Beiträge: 602

20.11.2009, 14:08:29 via Website

Nein, bin unter Win unterwegs...
Ich glaube fast ich habe irgendwo anders einen Fehler.. werde mich da nochmal in Ruhe dransetzen müssen.. kann gut sein, dass ich irgendwo einen Logik-Fehler habe (liege seit ein paar Tagen wegen Grippe flach)..
Danke für die tolle Hilfe soweit! :)

Antworten
Gelöschter Account
  • Forum-Beiträge: 22

20.11.2009, 16:03:52 via Website

Christoph Rado
(Das @Override mochte Eclipse nicht, stattdessen wollte er ein @SuppressWarnings("unused") dort haben - was auch immer das tut..)

Es sagt dir ganz exakt, wo der Fehler ist... @Override sagt, dass die Methode eine Methode mit gleicher Signatur der Superklasse überschreiben muss. @SuppressWarnings("unused") sagt, dass die Methode eigentlich von niemandem aufgerufen wird und daher überflüssig ist, du aber genau weißt, was du tust. Beides zusammen möchte dir sagen, dass du versehentlich eine falsche Methode überschrieben hast. :)

Die Methode, die du überschreiben möchtest, hat die Signatur "void handleMessage(Message msg)". Du schreibst "void handleMessage(int value)", was eine ganze andere Methode ist. Wenn du statt int ein Message übergibst, mag er auch das @Override wieder, und dein Handler sollte danach auch funktionieren.

Antworten
goto android
  • Forum-Beiträge: 138

20.11.2009, 16:48:08 via Website

Sorry, mein Fehler.
Hab den Parameter von handleMessage mit dem von sendEmtpyMessage verwechselt.

Antworten
Gelöschter Account
  • Forum-Beiträge: 602

20.11.2009, 17:30:49 via Website

Mein Bruder hat mir das nun mit einem handler.post(Runnable) gelöst. Der Handler wird schon in der Activity deklariert, somit schreibt der Handler über post() direkt in die Message Queue des Activity-Threads. Da die Activity auch die GUI updaten kann, funktoniert es somit.

1class AutoUpdateThread extends Thread {
2 public void run() {
3 while(true) {
4 try {
5 if (autoUpdate)
6 handler.post(new Runnable() {
7 @Override
8 public void run() {
9 refreshSystemInfo();
10 }
11 });
12 Thread.sleep(1000);
13 }
14 catch(InterruptedException e) {
15 autoUpdate = false;
16 }
17 }
18 }
19 }

PS: Formatierung des [code]-Tags ist ja noch nicht das grüne vom Ei. Auch kopieren ist hier nich, weil immer die Zeilennummern mitkopiert werden.
PPS: Werde mich nun erstmal meinem Buch (Android - Grundlagen und Programmierung) widmen, um mich ein bischen mehr an die Gegebenheiten unter Android zu gewöhnen... Kann ja nich angehn, dass ich hier schon scheitere :D

— geändert am 20.11.2009, 17:31:58

Antworten