2011-02-07 17 views
9

Piszę aplikację sportową, która musi śledzić upływ czasu w kwartale/pół/okresie. Upływający czas musi być dokładny do drugiego. Zegar gry musi nadal działać, nawet jeśli użytkownik jawnie umieszcza urządzenie w trybie uśpienia, naciskając przycisk zasilania.Zegar z Androidem, który działa, gdy urządzenie śpi

Moja pierwsza próba to zaangażowany użyciu Handler.postDelayed() wywołać zegar tyka co 200ms i WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON aby upewnić się, że „zegar” nie został zatrzymany przez Wygaszanie ekranu. Wkrótce jednak dowiedziałem się, że można obejść to podejście, naciskając przycisk zasilania, aby ręcznie uśpić urządzenie. Ponadto metoda postDelayed() doświadcza pewnego dryfu zegara, najwyraźniej wynikającego z czasu spędzonego w metodzie run(). Rzeczywiste liczby są nadal dokładne, ale zamiast być wyrównane, na przykład na 5-sekundowych granicach, które są łatwo zrozumiałe dla użytkowników - czasomierze zaczynają dryfować, co powoduje pewne zrozumiałe dezorientację użytkownika.

Po kilku badaniach znalazłem techiques do korzystania z usług, java timers, AlarmManager i PartialWakeLock do realizacji timerów. Usługi same w sobie nie rozwiążą problemu związanego ze spaniem urządzenia. Liczniki czasu Java, podobnie jak usługi, nie rozwiązują problemu z uśpieniem urządzenia. AlarmManager wydaje się być dobrym podejściem, ale obawiam się, że nie jest to właściwe użycie AlarmManagera (tj. Bardzo krótkie przerwy między alarmami). Korzystanie z PartialWakeLock również wygląda obiecująco, ale samo w sobie nie rozwiązuje problemu z dryftem zegara, którego doświadczam.

Mam zamiar wypróbować połączenie AlarmManager i PartialWakeLock. Pomysł polega na tym, że program AlarmManager pomoże w walce z dryfem zegara i PartialWakeLock, aby pomóc w uproszczeniu kodu (skrzyżowanie palców). Mam nadzieję, że takie podejście zapewni rozsądną równowagę pomiędzy oszczędzaniem energii, złożonością kodu i oczekiwaniami użytkowników. Wszelkie porady są mile widziane.

Dzięki,

Rich

+0

użyciu PartialWakeLock nie będzie widać żadnego dryfu, ale bateria będzie drenażu. – NitZRobotKoder

+0

Powiedziałeś, że "Czas, który upłynął, musi być dokładny do sekundy". Dlaczego nie używasz prostego czasu systemowego (jak System.currentTimeMillis())? Wystarczy zapisać znacznik czasu na początku, a następnie odjąć go od bieżącego czasu, gdy jest to potrzebne – Dmitry

Odpowiedz

4

Mam częściowe rozwiązanie mojego oryginalnego postu powyżej. Nie odnosi się jeszcze do dryfu zegara związanego z czasem spędzonym w obliczeniach podczas przetwarzania postDelayed(), ale jest to krok naprzód. Ponadto jest zwodniczo prosty, zawsze dobry znak.

Okazuje się, używałem SystemClock.uptimeMillis() kiedy należy Używam SystemClock.elapsedRealtime(). Różnica między 2 jest subtelna, ale ważna.

Jak można się spodziewać, moje rozwiązanie śledzi czas, jaki upłynął między gromadząc trwania połączeń do postDelayed() - czyli czas, jaki upłynął = ElapsedTime + lastClockInterval. Jak wspomniano powyżej, oryginalna implementacja używana uptimeMillis(). Uważne odczytanie numeru javadoc reveals that uptimeMillis() nie obejmuje czasu spędzonego w "głębokim śnie", np. Gdy użytkownik naciśnie przycisk zasilania. Jednak metodaupłynęła pod nazwą Realtime() i zawiera czas spędzony w trybie "głębokiego snu". Wszystko, co było potrzebne do śledzenia czasu w trakcie głębokich cykli snu, to zastąpienie czasu pracy z upływającego czasu pracy () z 30 minut przed upływem 30 minut() z upływem czasu trwania(). Powodzenie! Nie trzeba używać AlarmManager, PartialWakeLock ani niczego innego znacznie bardziej skomplikowanego. Oczywiście, metody te nadal mają zastosowanie, ale są one przesadne przy wdrażaniu prostego zegara lub licznika czasu.

Następnym problemem, który należy rozwiązać, jest dryft zegara spowodowany niezerowym czasem wykonania związanym z przetwarzaniem postDelayed(). Mam nadzieję, że zgłoszenie wątku do przetwarzania rozwiąże ten problem, umożliwiając postDelayed() mniej więcej naśladować wywołanie asynchroniczne. Innym podejściem byłoby dostosowanie czasu opóźnienia (postDelayed() w celu uwzględnienia czasu spędzonego w postDelayed(). Opublikuję moje wyniki.

W przypadku niepowiązanej notatki, podczas mojego dochodzenia potraktowałem siebie jako CommonsWare Warescription. Chociaż nie wykorzystałem bezpośrednio żadnych pomysłów z tego źródła dla tego problemu, myślę, że będzie to moje bezpośrednie źródło informacji na Androida w najbliższej przyszłości. Mam subskrypcję O'Reilly w ramach mojej codziennej pracy, ale znalazłem książki CommonsWare za tak samo dobre, jeśli nie lepsze, źródło informacji o rozwoju Androida jako o zasobach O'Reilly. I odkryłem, że zasoby O'Reilly Safari są całkiem dobre. Ciekawe ...

Cheers, Rich

Powiązane problemy