Android-Timer, der funktioniert, wenn das Gerät schläft

9

Ich schreibe eine Sport-App, die die verstrichene Zeit von Viertel / Hälfte / Periode verfolgen muss. Die verstrichene Zeit muss auf die Sekunde genau sein. Die Spieluhr muss weiterhin ausgeführt werden, auch wenn der Benutzer das Gerät explizit in den Energiesparmodus versetzt, indem er den Ein- / Ausschalter drückt.

Mein erster Versuch bestand darin, Handler.postDelayed () alle 200ms und WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON alle 200ms auszulösen, um sicherzustellen, dass die "Uhr" nicht vorhanden war Wurde nicht durch eine Bildschirm-Zeitüberschreitung gestoppt. Aber ich habe schnell gelernt, dass es möglich ist, diesen Ansatz zu umgehen, indem Sie den Ein- / Ausschalter drücken, um das Gerät manuell einzuschalten. Darüber hinaus erfährt der postDelayed () -Ansatz eine gewisse Zeitverschiebung, was offensichtlich auf die in der run () -Methode verbrachte Zeit zurückzuführen ist. Die tatsächlichen Zahlen sind immer noch genau, aber anstatt, zum Beispiel, auf 5-Sekunden-Grenzen ausgerichtet zu werden, die von Benutzern leicht verstanden werden - die beteiligten Timer beginnen zu driften, was zu einer verständlichen Benutzerverwirrung führt.

Nach ein wenig Recherche habe ich Techniken für die Nutzung von Diensten, Java-Timer , AlarmManager und PartialWakeLock um Timer zu implementieren. Dienste allein lösen das Problem nicht, das mit dem Einschlafen des Geräts verbunden ist. Java-Timer, wie Dienste, lösen das Problem nicht, wenn das Gerät in den Ruhezustand wechselt. AlarmManager scheint ein guter Ansatz zu sein, aber ich bin besorgt, dass dies keine angemessene Verwendung von AlarmManager ist (d. H. Sehr kurze Intervalle zwischen den Alarmen). Die Verwendung von PartialWakeLock sieht ebenfalls vielversprechend aus, aber an sich wird das Uhr-Drift-Problem nicht angesprochen.

Ich werde eine Kombination aus AlarmManager und PartialWakeLock versuchen. Die Idee ist, dass der AlarmManager helfen wird, den Uhr-Drift zu bekämpfen, und PartialWakeLock, um den Code einfach zu halten (Daumen drücken). Ich hoffe, dass dieser Ansatz zu einem vernünftigen Gleichgewicht zwischen Energieeinsparung, Code-Komplexität und Benutzererwartungen führt. Jeder Rat wird sehr geschätzt.

Danke,

Reich

    
Rich 07.02.2011, 05:00
quelle

1 Antwort

4

Ich habe eine Teillösung für meinen ursprünglichen Beitrag oben. Es behandelt noch nicht die mit der Zeit, die während der postDelayed () -Verarbeitung verbrachte Zeit verbundene Zeitabweichung, aber es ist ein Fortschritt. Außerdem ist es täuschend einfach, immer ein gutes Zeichen.

Es stellte sich heraus, dass ich SystemClock.uptimeMillis () verwendet habe, als ich SystemClock.elapsedRealtime () hätte verwenden sollen. Der Unterschied zwischen den 2 ist subtil, aber wichtig.

Wie Sie vielleicht erwarten, verfolgt meine Lösung die verstrichene Zeit, indem sie die Dauern zwischen den Aufrufen von postDelayed () - ansammelt, d. h. verstrichene Zeit = elapsedTime + lastClockInterval . Wie oben erwähnt, verwendete die ursprüngliche Implementierung uptimeMillis () . Ein sorgfältiges Lesen des javadoc zeigt, dass uptimeMillis () beinhaltet nicht die Zeit, die im "Tiefschlaf" verbracht wird, z. B. wenn der Benutzer den Ein- / Ausschalter drückt. Die Methode elapsedRealtime () enthält jedoch die Zeit, die im Modus "Deep Sleep" verbracht wurde. Alles, was erforderlich war, um die Zeit während der Tiefschlafzyklen zu verfolgen, war, die Verwendung von uptimeMillis () durch elapsedRealtime () zu ersetzen. Erfolg! Keine Notwendigkeit, AlarmManager, PartialWakeLock oder irgendetwas anderes wesentlich komplizierter zu verwenden. Zugegeben, diese Methoden sind zwar immer noch nützlich, aber sie sind übertrieben, wenn Sie eine einfache Zeituhr oder einen Timer implementieren.

Das nächste Problem, das es zu lösen gilt, ist die Taktverschiebung, die durch die Nicht-Null-Ausführungszeit verursacht wird, die mit der postDelayed () Verarbeitung verbunden ist. Ich hoffe, dass ein Thread, der die Verarbeitung ausführt, dieses Problem löst, indem postDelayed () mehr oder weniger einen asynchronen Aufruf nachahmt. Ein anderer Ansatz wäre, die Verzögerungszeit postDelayed () anzupassen, um die in postDelayed () verbrachte Zeit zu berücksichtigen. Ich werde meine Ergebnisse veröffentlichen.

Ich habe mich während meiner Untersuchung selbst mit einer CommonsWare-Rezeptur beschäftigt. Obwohl ich für dieses Problem nicht direkt Ideen aus dieser Quelle verwendet habe, denke ich, dass es auf absehbare Zeit meine Android Go-to-Informationsquelle sein wird. Ich habe ein O'Reilly-Abonnement durch meinen Job, aber ich habe festgestellt, dass die CommonsWare-Bücher eine mindestens genauso gute, wenn nicht sogar bessere Quelle für Informationen über die Android-Entwicklung als O'Reilly-Ressourcen sind. Und ich habe festgestellt, dass die Ressourcen der O'Reilly Safari ziemlich gut sind. Interessant ...

Prost, Reiche

    
Rich 09.02.2011, 04:47
quelle