Timer verbessern

  • 8 Antworten
  • Letztes Antwortdatum
M

MrParse

Neues Mitglied
0
heyhey
ich hab da ein Problem.. Bzw. eine Lösung die aber sehr umständlich aussieht.

Also, ich habe eine App geschrieben, die in einem gegebenen Zeitintervall jede Sekunde ein Rechteck auf einem Canvas vergrößert. Hat prima geklappt dazu habe ich einen zweiten Thread mit der Funktion eines Timers erstellt. Da das Rechteck nur jede Sekunde vergrößert wurde, habe ich den Thread jetzt nur noch 1ms pausiert anstatt der vorherigen 1000 um das Rechteck gleichmäßig zu vergößern. Tja, jetzt hat das ganze bei einem Intervall von 8000ms aber nicht mehr 8 Sekunden sondern mehr als das doppelte gedauert... Nach Internetrecherchen bin ich darauf gekommen, dass der aufruf sleep(1) länger als 1ms dauert.
Jetzt hatte ich mehrere Lösungsansätze, der letzte Funktioniert zwar, kommt mir aber sehr umständlich vor:

1: Systemzeit vor und nach dem sleep-Aufruf speichern und die verstrichene Zeit um die differenz der 2 Systemzeiten erhöhen -> der Vorgang dauert 8 Sekunden, das Rechteck wird aber ungleichmäßig erhöht.
2: Über FPS und TPS die Performance anpassen -> gleichmäßige Vergrößerung aber dauert wieder länger als 8sec.
3: CountDownTimer initialisieren und jede ms die verstrichene Zeit erhöhen.
-> klappt

Aus der verstrichenen Zeit wird der Betrag errechnet, um den das Recheck vergrößert werden soll.

Jetzt habe ich jedoch einen Thread, der seinerseits wieder einen CountDownTimer initialisiert und so lange er läuft die onDraw-Methode meiner View aufruft, jedoch mit der verstrichenen Zeit, die er vom CountDownTimer bekommt.
Geht das nich einfacher? Kann man den sleep-Befehl nicht "genauer" durchführen etc?:huh:

Gruß MrParse
 
Hey,
Und was ist wenn du 4x weniger Aufrufe startest und dafür sleep(4ms) setzt? :-D
Wahrscheinlich ist die Verarbeitung des Befehlssatzes einfach zu lang - halt, wie du schon sagst - länger als 1ms. Oder zur Not noch höhere Werte probieren.

Btw: so "fein" zu skalieren macht sowieso keinen Sinn. Ich glaube nicht mal Insekten haben so gute Augen (haben die überhaupt handelsübliche Augen? :-D), dass die 1000 Bilder in der Sekunde verarbeiten können..
Teile am besten mal so, dass du 50fps. Das reicht vollkommen aus und spart Ressourcen.

(400 schleifen a 20ms, sollten das nach meiner Rechnung sein - hoffentlich habe ich mich jetzt nicht verrechnet) :-D
 
Zuletzt bearbeitet:
Ja klar 1000 FPS braucht keiner. :D war halt ein Versuch.
Ich habe das ganze auch mit 100 FPS probiert aber gleiches Problem.. Hab übrigends grade gemerkt, dass der sleep-Aufruf manchmal "nur" 1 bis 2 ms Sekunden mehr braucht, also ist es wohl echt hauptsächlich mein Code der so lange dauert.
Danke für die Antwort ;)

Hätte da jetzt noch eine Frage: Ich habe das ja über einen CountDownTimer gelößt. Allerdings zählt der nicht immer bis zum Schluss runter :sad: Also bei einem countDownInterval von 10 hört er bei z.B. 17 auf und nicht 10.
Warum ist das so? Sogar bei einem countDownInterval von 1 hört er manchmal schon bei 3 auf :unsure:
 
Komisch...
Gerade kann ich mir ehrlich gesagt nur ganz schwer vorstellen, wie dein Code gerade aussieht^^
Kannst ihn ja mal auszugsweise hier einstellen.
 
eigentlich nichts exotisches :D

zum initialisieren des CountDownTimers ruft die View das auf:
Code:
public void createCountDownTimer(long sT,long invl){
        counter = new CountDown(sT, invl);
        breakValue= false;
    }
und in der run() meines Threads:
Code:
for(repetitionsDone=0;repetitionsDone<repetitions;repetitionsDone++){
                    counter.start();
                    while (this.theSeconds < (endSeconds - 5)) {  // -5 weil wie gesagt der CountDownTimer manchmal schon vor 1 aufhört...
                        if(breakValue){
                            break;
                        }

                        try {
                            theCanvas = theView.getHolder().lockCanvas();
                            synchronized (theView.getHolder()) {
                                theView.setSeconds(theSeconds);
                                theView.setToDo(2);
                                theView.onDraw(theCanvas);
                            }

                        } finally {
                            if (theCanvas != null) {
                                theView.getHolder().unlockCanvasAndPost(
                                        theCanvas);
                            }
                        }
                        theSeconds = endSeconds - (int) counter.getRemainingSeconds();
                    }
                    if(breakValue){
                        break;
                    }
                    theView.setSeconds(0);
                    this.theSeconds = theView.getSeconds();
                }
Das macht er dann so lange wie er laufen soll (wird über eine boolische Variable abgefragt). Alle Variablen sind Global initialisiert.

außerdem noch die CountDown Klasse:
Code:
public class CountDown extends CountDownTimer {
    Timer theTimer;
    long secUntilFinished;

    public CountDown(long startTime, long intervall) {
        super(startTime, intervall);        
    }

    @Override
    public void onFinish() {        
    }

    @Override
    public void onTick(long millisUntilFinished) {
        secUntilFinished=millisUntilFinished;
    }
    
    public long getRemainingSeconds(){
        return secUntilFinished;
    }
}

Also der Thread macht was in der run() steht so lange bis er aufhören soll und bei jedem Durchlauf holt er sich die verbleibende Zeit vom CountDownTimer, der parallel dazu läuft.
 
Leider ist der Code nicht vollständig.

Nur so aus Neugier, du startest den CountdownTimer immer wieder.

Code:
counter.start();
Beendest du den counter auch. Und was macht der Counter, wenn in der Activity die Methode onPause() aufgerufen wird.

Nachtrag:
Alle Variablen sind Global initialisiert.

Gobale Variablen widersprechen den Programmierkonzept von Java. Nur Schnittstellen sollten public sein.
 
Zuletzt bearbeitet:
Beendest du den counter auch. Und was macht der Counter, wenn in der Activity die Methode onPause() aufgerufen wird.
Jup der wird in der for-Schleife immer wieder gestartet wenn er bis zum Ende gelaufen ist.
Beendet wird er nach der for-Schleife, nach durchlauf dieser ist der Ablauf beendet.
Der Aufruf von onPause hat keinen Einfluss auf den Counter, der Thread sowie der Counter sollen bei ausgeschaltetem Display weiterlaufen.

Gobale Variablen widersprechen den Programmierkonzept von Java. Nur Schnittstellen sollten public sein.
Die globalen Variablen der jeweiligen Klasse sind "private", sorry hab ich vergessen zu erwähnen. Das entspricht ja dem Programmierkonzept von java oder?
 
Wenn Du den counter neu startest, muss du ihn vorher beenden. Du beendest den alten Thread nicht, indem du einen neuen startest. Dafür ist die Methode cancle() da.

Am besten setzt du den counter dann gleich null, und erzeugst dann einen neuen counter. Den du dann wieder startest.

Du muss den counter auch beenden, wenn die Activity in Hintergrund geht oder beendet wird, sonst läuft der Thread einfach weiter. Die Folge ist meist ein NullPointerException.
 
Alles klar wird umgesetzt :) danke
 
Zurück
Oben Unten