# keine TextView-Aktualisierung in der while-Schleife



## Gast2 (12. Sep 2012)

erst der Quelltext:
	
	
	
	





```
public class MainActivity extends Activity {

	TextView txv;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        txv = (TextView) findViewById(R.id.ausgabe);
        long now;

		while (true) {
			now = System.nanoTime();
			txv.setText(String.valueOf(now));
		}
    }
}
```

Was würdest Du erwarten?
Ich erwarte, dass ich kontinuierlich den aktuellen Timestamp angezeigt bekomme.
Aber der Bildschirm bleibt leer.

Egal, welchen Text ich in innerhalb der while-Schleife dem txv zuweise, er wird nicht angezeigt.
Wenn ich die while(){} auskommentiere, sehe ich den Originaltext.

Warum wird nichts angezeigt??? ???:L


----------



## schlingel (12. Sep 2012)

Ich würde erwarten, dass das System anzeigt, dass sich die App aufgehängt hat und mir einen Force-Close-Dialog anzeigen.

Warum du allerdings dorthin gar nicht kommst ist mir ein Rätsel. Wird die App wirklich aufgerufen? Aktuelle Version schon am Gerät/Emulator?


----------



## Gast2 (12. Sep 2012)

schlingel hat gesagt.:


> Warum du allerdings dorthin gar nicht kommst ist mir ein Rätsel. Wird die App wirklich aufgerufen?



Ja. Ich habe den Quelltext geändert nach:
	
	
	
	





```
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        txv = (TextView) findViewById(R.id.ausgabe);
        
        long now = System.nanoTime();        
		long end = now + 2000000000;
		
		txv.setText("Anfang");
		
		while (System.nanoTime() < end ) {
			txv.setText(String.valueOf(now));
		}
		
		txv.setText("Ende");
    }
```

Nach zwei Sekunden weiser Bildschirm erscheint "Ende".
Ergo, das Programm läuft. Nur werden Textzuweisungen innerhalb der Schleife nicht gezeigt. 
Übrigens auch nicht in do while oder if -Schleifen.


----------



## schlingel (12. Sep 2012)

Hier solltest du mit Threads arbeiten. Oder noch besser einfach nur ne Animation anzeigen.


----------



## Gast2 (12. Sep 2012)

Nun ja,

*aber warum wird innerhalb der Schleife die Änderung der Werte nicht übernommen.*
Dieses Problem habe ich schön öfters gesehen, aber keine Lösung dafür.

Schleifen kommen immer wieder vor und innerhalb der Schleifen sollten doch Anweisungen möglich sein, die sofort ausgeführt werden?!


----------



## schlingel (12. Sep 2012)

Schau dir noch einmal an für was genau onCreate da ist ;-)

Die UI wird sichtbar sobald onCreate fertig ist.


----------



## Gast2 (12. Sep 2012)

schlingel hat gesagt.:


> Die UI wird sichtbar sobald onCreate fertig ist.



Ich habe es nicht nur in eine externe Methode gesteckt, auch in eine externe Klasse.
Habe diese innerhalb von onCreate aufgerufen.
Und trotz dem funktioniert es nicht.


----------



## schlingel (12. Sep 2012)

Folgendes (zugegebenermaßen blödes) Gleichnis:
- Du stehst im Wohnzimmer und winkst deiner Freundin. Deine Hand befindet sich im Wohnzimmer.
- Du stehst im Wohnzimmer und ziehst dir Handschuhe an und winkst. Ist deshalb deine Hand nicht mehr im Wohnzimmer?

Wenn du also ne Methode einer dritten Klasse innerhalb der onCreate-Methode aufrufst, bist du noch immer in der onCreate-Methode.


----------



## Gast2 (13. Sep 2012)

schlingel hat gesagt.:


> Wenn du also ne Methode einer dritten Klasse innerhalb der onCreate-Methode aufrufst, bist du noch immer in der onCreate-Methode.



Ja genau! 
Aber das gesamte Programm läuft doch in der onCreate-Methode, 
es geht mal in eine andere Klasse 
oder zieht sich auch mal Handschuhe an,
aber es verlässt doch die onCreate nie.
Außer das Programm ist zu Ende.

Ich habe überhaupt keine Vorstellung, wie etwas unabhängig von der onCreate laufen kann.

Hier noch so ein Beispiel:

```
public class MainActivity extends Activity implements OnClickListener {

	Button btn_start;
	TextView txv_text;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        btn_start = (Button) findViewById(R.id.btn_start);
        btn_start.setOnClickListener(this);
        
        txv_text = (TextView) findViewById(R.id.txv_p1_maincontend);
    }

	@Override
	public void onClick(View v) {
		for (int i = 0; i < 3; i++) {			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}					
			txv_text.setText("zählen");			
		}		
		txv_text.setText("ENDE");
	}	
}
```

Nach dem Button-Klick passiert drei Sekunden nichts und dann steht im TextView "ENDE".
(Statt "0", "1", "2", "ENDE")

Soll da wirklich nur ein zweiter Thread helfen??? ???:L


----------



## Gast2 (13. Sep 2012)

Ich arbeite mich in den Thread Gedanken ein,
aber auch hier bekomme ich ein null-pointer-exception in Zeile 22:
	
	
	
	





```
public class MainActivity extends Activity {

	TextView text;
	String zahl;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        
        Runnable r = new Runnable(){

			@Override
			public void run() {
		        text = (TextView) findViewById(R.id.txv_info);
				for (int i = 0; i < 6; i++) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					zahl = String.valueOf(i);
					text.setText(zahl);	
				}			
			}        	
        };
        Thread t = new Thread(r);
        t.start();
    }
}
```
Den TextView habe ich testweise innerhalb und außerhalb deklariert,
text.setText() auch mit einfachen String belegt ("Hallo"),
alle Versuche waren ohne Erfolg.
*
Warum kann ich keinen Text zuweisen (und anzeigen) lassen?*


----------



## VfL_Freak (13. Sep 2012)

Moin,

vermutlich ist "text" gleich null !
Versuch's dochmal so:

```
public void run() 
{
    text = (TextView) findViewById(R.id.txv_info);
    if( text != null ) // !!!
    {
        for (int i = 0; i < 6; i++) 
        {
            try 
            {
                Thread.sleep(1000);
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
            zahl = String.valueOf(i);
            text.setText(zahl); 
    }
}
```

Gruß
Klaus


----------



## schlingel (13. Sep 2012)

> Aber das gesamte Programm läuft doch in der onCreate-Methode[...]


Nein! Wie kommst du denn auf diese Idee?

Schau dir mal den Activity-Lifecycle an:






onCreate ist nur die erste Methode die aufgerufen wird wenn die Activity erzeugt wird. Sobald die Activitiy dann läuft, reagiert sie einfach nur noch auf Events. Die können vom Benutzer kommen oder vom System, z.B. um die Activity zu beenden oder zu pausieren.

Die NPE bekommst du, weil du hier nicht das Layout für die Activity gesetzt hast. (Der Aufruf von setContentView fehlt) Abgesehen davon, würdest du gleich die nächste Exception bekommen wenn du versuchst aus einem anderen Thread als dem UI-Thread auf die UI zuzugreifen.

Dazu müsstest du das ganze so machen:


```
public class MainActivity extends Activity {
 
    TextView text;
    String zahl; // warum muss das eigentlich eine Instanzvariable sein?
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        
        setContentView(R.layout.deineContentView);
        text = (TextView) findViewById(R.id.txv_info);

        Runnable r = new Runnable(){
 
            @Override
            public void run() {
                for (int i = 0; i < 6; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    zahl = String.valueOf(i);
                    // mit post kannst du der View sagen, dass sie sich mit dem UI-Thread
                    // synchronisieren soll und das Runnable innerhalb des UI Threads ausführt
                    text.post(new Runnable() {
                      text.setText(zahl);                       
                    });

                }           
            }           
        };
        Thread t = new Thread(r);
        t.start();
    }
}
```


----------



## Gast2 (14. Sep 2012)

alles was ich soeben geschrieben habe,
nehme ich zurück.


----------



## schlingel (14. Sep 2012)

schlingel hat gesagt.:
			
		

> Abgesehen davon, *würdest du gleich die nächste Exception bekommen wenn du versuchst aus einem anderen Thread als dem UI-Thread auf die UI zuzugreifen*.



=> Siehe Code den ich geposted habe, ist der so drinnen? Und holst du dir die Referenz noch im onCreate (findViewById) oder schon im Thread? Sollte nämlich im onCreate passieren.


```
text.post(new Runnable() {
                      text.setText(zahl);                       
                    });
```

Du bekommst nämlich keine NullPointerException sondern die angesprochene "nächste" Exception. CalledFromWrongThreadException, steht ja sogar im Logcat drinnen.


----------



## Gast2 (14. Sep 2012)

schlingel hat gesagt.:


> => Siehe Code den ich geposted habe, ist der so drinnen?
> 
> Du bekommst nämlich keine NullPointerException sondern die angesprochene "nächste" Exception. CalledFromWrongThreadException, steht ja sogar im Logcat drinnen.



Ja,
Entschuldigung bitte, hab ich nicht gleich korrekt übernommen,
irgendwann fiel mir ein, dass ich in Deinem Quelltext etwas von einer Übergabe gelesen habe. Dann sah ich's.

Nun bekomme ich Fehler im Quelltext angezeigt in Zeile text.setText(zahl); gleich zwei Meldungen



> Multiple markers at this line
> - Syntax error on token "zahl", VariableDeclaratorId expected after
> this token
> - Syntax error on token(s), misplaced construct(s)



...was ich nicht nachvollziehen kann, 
da ja der TextView text oben deklariert wurde.

Muss ich das text.post ausserhalb von Runnable(){} irgendwie entgegennehmen?


----------



## Gast2 (14. Sep 2012)

VfL_Freak hat gesagt.:


> vermutlich ist "text" gleich null !



Ne, is nich null.
Nach 5 Sekunden warten wird der Text erst eingeblendet (mit einer "5").
Die Werte dazwischen werden nicht dargestellt.


----------



## schlingel (14. Sep 2012)

Irgendwo passt was nicht mit deinen Sichtbarkeiten. Wo genau weiß ich nicht, aber bei mir funktionieren diese Varianten:

main.xml
[xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    androidrientation="vertical" >

    <TextView
        android:id="@+id/lblSeconds"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="0" />

</LinearLayout>
[/xml]

TestprojectActivity.java

```
public class TestprojectActivity extends Activity {
	
	private TextView lblSeconds;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lblSeconds = (TextView)findViewById(R.id.lblSeconds);
//        Hier die etwas elegantere Variante mit dem AsyncTask
//        AsyncTask<Void, Integer, Void> t = new AsyncTask<Void, Integer, Void>() {
//        	@Override
//        	protected Void doInBackground(Void... params) {
//        		int i = 0;
//        		long timestamp = System.currentTimeMillis();
//        		
//        		while(i < 5) { /* busy waiting ist böse, aber soll auch nur ein beispiel sein */
//        			if(System.currentTimeMillis() - timestamp >= 1000) {
//        				i++;
//        				timestamp = System.currentTimeMillis();
//        				publishProgress(i);
//        			}
//        		}
//        		
//        		return null;
//        	}
//        	@Override
//        	protected void onProgressUpdate(Integer... values) {
//        		lblSeconds.setText(Integer.toString(values[0]));
//        	}
//        	
//        	@Override
//        	protected void onPostExecute(Void result) {
//        		Toast.makeText(TestprojectActivity.this, "Fertig!", Toast.LENGTH_SHORT).show();
//        	}
//        };
//        
//        t.execute();
        
//     Hier die Variante mit dem Thread.
        new Thread(new Runnable() {
                // das muss eine instanzvariable des Runnable sein, weil ich sonst in den anonymen Runnable
                // für die Updates nicht darauf zugreifen kann.
        	int i = 0;
        	
			public void run() {
				for(i = 0; i < 5; i++) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					// immer brav post verwenden, sonst gibt's eine Exception
					lblSeconds.post(new Runnable() {
						public void run() {
							lblSeconds.setText(Integer.toString(i));
						}
					});
				}
				lblSeconds.post(new Runnable() {
					public void run() {
						Toast.makeText(TestprojectActivity.this, "Fertig!", Toast.LENGTH_SHORT).show();
					}
				});
			}
		}).start();
    }
}
```


----------



## Gast2 (14. Sep 2012)

@Schlingel:

also die nicht auskommentierte Variante funktioniert. 
Das macht mich heute (nachdem ich nicht so erfolgreich war) sehr glücklich! 

Was nun genau mein Fehler war, weiß ich nicht.
Ich habe mein relativeLayout zum LinearLayout umgebaut und
Deinen Quelltext kopiert.

Im Quelltext fiel mir auf, dass eine Klammer jetzt anders steht.

                            lblSeconds.setText(Integer.toString(i));
*}*
                    });

Die fett markierte Klammer hatte ich zuvor an anderer Stelle.

Nun werde ich mir noch den auskommentierten Quelltext anschauen...

Vielen Dank! :toll:


----------



## Gast2 (14. Sep 2012)

*Toll, toll, toll,*

auch die zweite AsyncTask-Variante läuft.
Du hast ja sogar meinen gestrigen Versuch mit dem timeStamp eingebaut. 

Den habe ich aber (weil 'n bissl böse) mit Thread.sleep() ausgetauscht.

Für meine Arbeit brauche ich tatsächlich zwei Counter,
einen der anzählt ("Achtung gleich geht's los...!")
und einen zweiten, der eine Messung stoppen soll nach einer bestimmten Zeit
und der sollte wohl mgl. in einen zweiten Thread laufen. 
Vielleicht bekomme ich das ja hin (nächste Woche.

*Danke und schönes Wochenende! *


----------

