2011-02-07 13 views
9

Sto scrivendo un'app per lo sport che deve tracciare il tempo trascorso di un quarto/metà/periodo. Il tempo trascorso deve essere accurato al secondo. Il cronometro di gioco deve continuare a funzionare anche se l'utente pone esplicitamente il dispositivo in modalità di sospensione premendo il pulsante di accensione.Timer Android che funziona quando il dispositivo dorme

Il mio primo tentativo di questo ha coinvolto utilizzando Handler.postDelayed() per attivare l'orologio zecche ogni 200ms e WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON per garantire che l ' "orologio" non è stato fermato da un timeout dello schermo. Ma presto ho appreso che era possibile aggirare questo approccio premendo il pulsante di accensione per mettere manualmente il dispositivo in modalità sospensione. Inoltre, l'approccio postDelayed() sta sperimentando una deriva del clock, apparentemente un risultato del tempo trascorso nel metodo run(). I numeri reali sono ancora accurati, ma invece di essere allineati, ad esempio, su confini di 5 secondi che sono facilmente comprensibili dagli utenti - i timer coinvolti iniziano a subire deriva, causando una comprensibile confusione dell'utente.

Dopo un po 'di ricerca ho trovato le tecniche per l'utilizzo dei servizi, java timers, AlarmManager e PartialWakeLock per implementare i timer. I servizi da soli non risolvono il problema associato al dispositivo che va a dormire. I timer Java, come i servizi, non risolvono il problema con il dispositivo che va a dormire. AlarmManager sembra un buon approccio, ma temo che non si tratti di un uso appropriato di AlarmManager (ovvero intervalli molto brevi tra gli allarmi). Anche l'uso di PartialWakeLock sembra promettente, ma di per sé non affronta il problema della deriva oraria che sto vivendo.

Ho intenzione di provare una combinazione di AlarmManager e PartialWakeLock. L'idea è che AlarmManager aiuterà a combattere la deriva del clock e PartialWakeLock per mantenere il codice semplice (incrociato con le dita). Spero che questo approccio si traduca in un ragionevole equilibrio tra risparmio energetico, complessità del codice e aspettative degli utenti. Qualsiasi consiglio è molto apprezzato.

Grazie,

Rich

+0

utilizzando PartialWakeLock non vedrete alcuna deriva, ma la batteria si scaricherà. – NitZRobotKoder

+0

Hai detto che "il tempo trascorso deve essere preciso al secondo". Perché non usi un semplice tempo di sistema (come System.currentTimeMillis()) ?? Basta salvare il timestamp all'avvio e quindi sottrarlo dall'ora corrente quando necessario – Dmitry

risposta

4

Ho una soluzione parziale al mio post originale sopra. Non ha ancora risolto la deriva del clock associata al tempo impiegato nei calcoli durante l'elaborazione postDelayed(), ma è un passo avanti. Inoltre, è ingannevolmente semplice, sempre un buon segno.

Si scopre che stavo usando SystemClock.uptimeMillis() quando avrei dovuto usando SystemClock.elapsedRealtime(). La differenza tra i 2 è sottile, ma importante.

Come ci si potrebbe aspettare, la mia soluzione tiene traccia del tempo trascorso accumulando durate tra le chiamate a postDelayed() - vale a dire, il tempo trascorso = elapsedTime + lastClockInterval. Come indicato sopra, l'implementazione originale ha utilizzato uptimeMillis(). Un'attenta lettura dello javadoc reveals that uptimeMillis() non include il tempo trascorso in "deep sleep", ad es. Quando l'utente preme il pulsante di accensione. Ma il metodo elapsedRealtime() include il tempo trascorso in modalità "deep sleep". Tutto ciò che è stato necessario per tracciare il tempo attraverso cicli di sonno profondo è stato quello di sostituire l'uso di uptimeMillis() con trascorso(). Successo! Non è necessario utilizzare AlarmManager, PartialWakeLock o qualsiasi altra cosa sostanzialmente più complicata. Certo, questi metodi hanno ancora degli usi, ma sono eccessivi quando si implementa un semplice orologio o timer.

Il prossimo problema da affrontare è con la deriva del clock causata dal tempo di esecuzione diverso da zero associato all'elaborazione postDelayed(). Spero che la generazione di una discussione per eseguire l'elaborazione risolverà questo problema, consentendo a postDelayed() di simulare più o meno una chiamata asincrona. Un altro approccio sarebbe quello di regolare il tempo di ritardo postDelayed() per tenere conto del tempo trascorso in postDelayed(). Posterò i miei risultati

Su una nota non correlata, durante la mia indagine mi sono trattato di un CommonsWare Warescription. Anche se non ho usato direttamente le idee di questa fonte per questo problema, penso che sarà la mia fonte di informazioni go-to Android per il prossimo futuro. Ho un abbonamento a O'Reilly durante il mio lavoro diurno, ma ho trovato i libri di CommonsWare come la migliore, se non migliore, fonte di informazioni sullo sviluppo di Android come le risorse O'Reilly. E ho trovato che le risorse di O'Reilly Safari sono piuttosto buone. Interessante ...

Cheers, Rich

Problemi correlati