2011-02-07 13 views
9

Estoy escribiendo una aplicación deportiva que necesita rastrear el tiempo transcurrido de cuarto/medio/período. El tiempo transcurrido debe ser exacto al segundo. El reloj del juego debe continuar ejecutándose incluso si el usuario coloca el dispositivo en modo de suspensión presionando el botón de encendido.Temporizador Android que funciona cuando el dispositivo está durmiendo

Mi primer intento en este implicó el uso de Handler.postDelayed() para activar el reloj avanza cada 200 ms y WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON para asegurar que el "reloj" no fue detenido por un tiempo de espera de pantalla. Pero pronto aprendí que era posible eludir este enfoque presionando el botón de encendido para poner el dispositivo a dormir de forma manual. Además, el enfoque postDelayed() está experimentando una deriva de reloj, aparentemente como resultado del tiempo empleado en el método run(). Los números reales siguen siendo precisos, pero en lugar de alinearse, por ejemplo, en límites de 5 segundos que los usuarios entienden fácilmente, los temporizadores involucrados comienzan a desviarse, lo que genera una confusión comprensible para el usuario.

Después de investigar un poco encontré técnicas para usar los servicios, java timers, AlarmManager y PartialWakeLock para implementar temporizadores. Los servicios por sí solos no resolverán el problema asociado con el dispositivo que se va a dormir. Los temporizadores de Java, como los servicios, no resuelven el problema con el dispositivo que se va a dormir. AlarmManager parece ser un buen enfoque, pero me preocupa que este no sea un uso apropiado de AlarmManager (es decir, intervalos muy cortos entre alarmas). El uso de PartialWakeLock también parece prometedor, pero por sí mismo no soluciona el problema de la deriva del reloj que estoy experimentando.

Voy a probar una combinación de AlarmManager y PartialWakeLock. La idea es que AlarmManager ayude a combatir la deriva del reloj y ParcialWakeLock para ayudar a mantener el código simple (con los dedos cruzados). Espero que este enfoque resulte en un equilibrio razonable entre la conservación de energía, la complejidad del código y las expectativas del usuario. Cualquier consejo es muy apreciado.

Gracias,

Rich

+0

usando PartialWakeLock no verá ninguna desviación, pero su batería se agotará. – NitZRobotKoder

+0

Usted dijo que "el tiempo transcurrido debe ser preciso para el segundo". ¿Por qué no usa la hora del sistema simple (como System.currentTimeMillis()) ?? Solo guarde la marca de tiempo al inicio y luego restela de la hora actual cuando sea necesario – Dmitry

Respuesta

4

que tengo una solución parcial a mi post original anterior. Todavía no se ocupa de la deriva del reloj asociada con el tiempo empleado en los cálculos durante el procesamiento postDelayed(), pero es un paso adelante. Además, es engañosamente simple, siempre es una buena señal.

Resulta que yo estaba usando SystemClock.uptimeMillis() cuando debería haber estado usando SystemClock.elapsedRealtime(). La diferencia entre los 2 es sutil, pero importante.

Como era de esperar, mi solución rastrea el tiempo transcurrido por la acumulación de duraciones entre llamadas a postDelayed() - es decir, el tiempo transcurrido = elapsedTime + lastClockInterval. Como se indicó anteriormente, la implementación original usó uptimeMillis(). La lectura cuidadosa del javadoc reveals that uptimeMillis() no incluye el tiempo que se pasa en "sueño profundo", por ejemplo, cuando el usuario presiona el botón de encendido. Pero el método elapsedRealtime() incluye el tiempo empleado en el modo "sueño profundo". Todo lo que se requería para rastrear el tiempo en los ciclos de sueño profundo era reemplazar el uso de uptimeMillis() con elapsedRealtime(). ¡Éxito! No es necesario usar AlarmManager, PartialWakeLock o cualquier otra cosa mucho más complicada. Por supuesto, estos métodos todavía tienen usos, pero son exagerados cuando se implementa un reloj o temporizador simple de tiempo transcurrido.

El siguiente problema que se debe resolver es la deriva del reloj provocada por el tiempo de ejecución distinto de cero asociado con el procesamiento postDelayed(). Espero que el engendrar un hilo para hacer el procesamiento resuelva este problema, permitiendo postDelayed() para imitar más o menos una llamada asincrónica. Otro enfoque sería ajustar el posDelayed() tiempo de retardo para tener en cuenta el tiempo pasado en postDelayed(). Publicaré mis resultados.

En una nota no relacionada, durante mi investigación me di el gusto de un CommonsWare Warescription. Si bien no usé directamente ninguna idea de esta fuente para este problema, sí creo que va a ser mi fuente de información de Android para el futuro previsible. Obtuve una suscripción a O'Reilly en mi trabajo diario, pero descubrí que los libros de CommonsWare son, al menos, tan buenos, sino mejores, fuente de información sobre el desarrollo de Android como los recursos de O'Reilly. Y descubrí que los recursos de O'Reilly Safari son bastante buenos. Interesante ...

Cheers, Rich

Cuestiones relacionadas