View aus externem Thread neu zeichnen

Hallo
Ich zeichne in der onDraw vom View so Zeug und immer wenn ich es neu zeichnen will benutze ich invalidate(). Nur geht das aus einem externen Thread nicht(Da kommt ein Fehler), also suche ich nach einer Möglichkeit von meinem selbst erzeugten thread aus den View neuzuzeichnen.

Welcher Fehler kommt denn?

Ich denke, dass es für Android-Apps ein Äquivalent zu SwingUtilities.invokeLater() gibt, dass schon versucht?

bye
TT

Das Äquivalent heißt runOnUiThread(java.lang.Runnable). Ansonsten gibts es noch ein paar andere Möglichkeiten: https://developer.android.com/training/multiple-threads/communicate-ui.html

Wie immer gilt: There’s a pattern for that.

Wenn du das Zeichnen nicht im UI-Thread erledigen willst, solltest du eine SurfaceView verwenden. Hier gibt’s ein Beispiel dafür: SurfaceView Example.

Wenn’s tatsächlich nur um das anstoßen des Zeichenvorgangs geht, gibt’s postInvalidate

Ich möchte damit eine Animation machen, aber es hängt irgendwie hinterher, so ist eine Aimation, bei der alle 200 ms sich etwas um 10 px verschieben sollte, so, dass sich nur ungefähr jede Sekunde das bild um vielleicht 50 px verschiebt.

v.Animation = true;
v.postInvalidate();
			while(v.legePos.x > 300){
				v.legePos.x -= 10;
				v.postInvalidate();
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		v.Animation = false;
		v.postInvalidate();

Im view wird einfach wenn Animation true ist ein bild auf die Position legePos gezeichnet

postInvalidate sagt ja nur, dass der UI-Thread bei Gelegenheit doch bitte einmal sich neu zeichnen soll. Wie du selber merkst, kann es sein, dass da Updates übersprungen werden weil es sich das Redraw nicht ausgegangen ist. Für das was du vorhast, ist wahrscheinlich eine SurfaceView eher geeignet.

Ich habe jetzt einen SurfaceView, aber diese Verzögerung ist sogar noch schlimmer als vorher. Ich benutze einen neuen Thread, der alles immer wieder neu zeichnet.


getHolder().addCallback(this);
new Thread(new Runnable(){
			@Override
			public void run(){
				while(!a.ende){
					if(holder != null){
						draw();
					}
				}
			}
		}).start();


	public void draw(){
		Canvas  c = 
		holder.lockCanvas();
		if(view == 0){
			paintMenue(c);
		}
		else if(view == 1){
			paintGame(c);
		}
		else if(view == 2){
			paintList(c);
		}
		else if(view == 3){
			paintOptions(c);
		}
		holder.unlockCanvasAndPost(c);
	}


@Override
	public void surfaceCreated(SurfaceHolder holder) {
		this.holder = holder;
		draw();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		this.holder = holder;
		draw();
	}

Wieso zeichnet deine View 3 verschiedene Dinge? Was macht die?

Wenn man knöpfe drückt wird die int view geändert, am anfang ist sie 0.Bei paintMenue wird das Hauptmenü gezeichnet. Bei paintGame das Spiel an sich und so weiter.

Hm, sorry. Ich weiß auch nicht woran das liegt. Wieviele FPS hat denn dein Zeichen-Thread?

Ich berechne die FPS-Rate so bei jedem Schleifendurchlauf:


long delta = System.nanoTime()-last;
last = System.nanoTime();
FPS = ((long) 1e9)/delta;
Log.i("FPS", Float.toString(FPS));

Sie ist 1.

Für was steht

U 1e9[/U]
?
Sollte 1e9 für neun stellen nach der 1 stehen, müsstest du trotzdem delta durch 1e9 rechnen, oder?

Und als Nebenfrage: Warum Float? Wäre Double nicht besser bzw. übersichtlicher?

1e9 steht für 1000000000 und dient der Umrechnung von Nanosek. in Sek. und mit double ist es immernoch 1.0
Diese FPS-Methode funktioniert bei meinen anderen Programmen auch.

Wann lässt du die denn laufen?
Denn ich befürchte du lässt die bei jedem Durchgang laufen, aber dann bekommst du doch nur raus wie viele sekunden du benötigt hast und nicht wie viele Frames du pro sekunde hast.

Direkt in der Schleife:


while(!a.ende){
			if(holder != null){
				long delta = System.nanoTime()-last;
				last = System.nanoTime();
				FPS = ((long) 1e9)/delta;
				Log.i("FPS", Double.toString(FPS));
				draw();
			}
		}

Also ich weiß nicht warum diese Methode jemals funktioniert hat aber wenn du das so machen willst dann musst du deine FPS noch mal 60 nehmen.
Du ziehst ja nur last von NOW ab. Das ergibt nur die Differenz

Und ich teile 10000000000 durch delta. Wie würdest du es denn machen ?

Ich würde die Durchgänge zählen bis eine Sekunde (oder halbe) um ist und dann gebe ich das aus. (PS: hab ich erst ein mal gebraucht)
Und ich hab mir deine Methode nochmal angeschaut und sie ausprobiert. Kann es einfach nur sein das dein Programm nur 1 FPS hat??
Bei mir funzt die nämlich.

Ich sag ja sie funktioniert und deswegen hat das Programm wahrscheinlich nur 1 FPS und das ist dann das Problem, das es zu beheben gilt

Mach doch villeicht einfach nur System.currentTimeMillis() das sind dann nur Millisekunden. Ist villeicht besser als NanoTime. Und übringens wenn du es z.B. mit millisekunden machst, mach “delta * 0.0001”.
Denn Mal rechnen ist schneller als Geteilt rechnen