2013-01-18 7 views
5

Mam pytanie dotyczące widżetów Androida, a zwłaszcza usług Androida. Oto, co chcę zrobić: na telefonie użytkownik powinien mieć możliwość dodania mojego widżetu do ekranu głównego. Widżet pobiera dane z sieci. Po przeczytaniu kilku tutoriali o tym dowiedziałem się, że najlepszym sposobem byłoby stworzenie usługi, która pobiera dane z sieci (gniazda TCP), a następnie aktualizuje widget w sposób ciągły. Odbywa się to za pomocą ScheduledExecutorService, która wykonuje Runnable w określonym przedziale czasu. Runnable łączy się z serwerem, pobiera dane i powinien zaktualizować widget).Android - zaktualizuj widżet do usługi za pomocą danych z sieci. Najlepsze podejście?

Mój problem polega na tym, że widżet nie musi być aktualizowany, gdy ekran jest wyłączony, więc usługa nie powinna działać z powodu wyczerpania baterii. Moje pytanie brzmi: jak to zrobić najlepiej?

znalazłem 2 podejścia, które bardziej lub mniej robić, co chcę:

  1. Kiedy pierwsza instancja widget zostanie dodana do ekranu głównego, to zarejestrować Odbiornik radiowy, który odbiera ACTION_SCREEN_ON i ACTION_SCREEN_OFF zamierzone działanie z systemu operacyjnego Android. Jeśli ACTION_SCREEN_ON zostanie uruchomiony, uruchomi usługę Updater, w przeciwnym razie ją zatrzyma. Ale nie jestem pewien, czy to dobre podejście ze względu na czas życia odbiornika telewizyjnego.

  2. W Runnable usługi Updater, która jest wykonywana okresowo przez ScheduledExecutorService i faktycznie robi rzeczy sieciowe, sprawdzam za pomocą PowerManager.isScreenOn(), jeśli ekran jest włączony. Jeśli tak, wykonuję kod sieci, w przeciwnym razie nie. Ale co się dzieje, gdy urządzenie jest w trybie gotowości? Czy ten kod jest wtedy wykonywany? A co z odpływem baterii?

Czy istnieje podejście "najlepszej praktyki" do tego, co chcę zrobić? Czytałem dużo o programie AlarmManager i jest to bardzo potężne narzędzie. Czy możesz zaplanować zadania w ten sposób, że są one wykonywane tylko wtedy, gdy wyświetlacz jest włączony?

Dzięki za pomoc.

Pozdrawiam NiThDi (na ekranie manipulacja widget i transmisje OFF)

+0

Czy zastanawiałeś się nad [Google Cloud Messaging] (http://developer.android.com/google/gcm/index.html)? W ten sposób nie będziesz musiał odpytywać danych (nawet jeśli tylko urządzenie jest obudzone) i będziesz otrzymywać nowe dane tylko po zmianie. Dodatkowo uzyskasz korzyści z wyświetlania najnowszego fragmentu, gdy użytkownik przebudzi swoje urządzenie, bez żadnych początkowych opóźnień. – Audrius

+0

Witam, dziękuję za szybką odpowiedź. Nie sądzę, że Google Cloud Messaging może robić, co chcę. Chodzi o to (aby się upewnić), że wspomniany serwer nie jest JEDNYM serwerem dla wszystkich użytkowników. Jest to aplikacja serwerowa działająca na ich komputerach. W rzeczywistości ta aplikacja jest pilotem, który łączy się z serwerem na komputerze w sieci LAN przez TCP/IP. – NiThDi

Odpowiedz

3

Pierwszym rozwiązaniem tego problemu jest droga. Uruchom nową IntentService dla komunikacji w tle z serwerem aplikacji. Po zakończeniu wyślij swój niestandardowy komunikat "Completed" z wynikami, a następnie obsłuż go w swoim widżecie.

Dodatkową korzyścią jest to, że wiele wystąpień widgetu działa z jednego "źródła" i nie zużyje żadnych zasobów w przypadku, gdyby użytkownik nie dodawał żadnych widżetów.

UPDATE Jak to jest możliwe, aby korzystać z ekranu ON/OFF transmisje z widgetu, to pewnie używać this (AlarmManager z ELAPSED_REALTIME (nie ELAPSED_REALTIME_WAKEUP) alarmu), aby zaplanować (intent) Uruchom serwisowym. W ten sposób twoja usługa nie zostanie zaplanowana, gdy ekran jest wyłączony, ale będzie uruchamiana okresowo, gdy jest włączona. A jeśli opóźnienie pomiędzy włączeniem i wyłączeniem ekranu jest dłuższe niż okres czasu, zostanie ono uruchomione natychmiast po ponownym włączeniu ekranu.

Jeśli chodzi o pytanie dotyczące czasu życia odbiorników, jak wspomniano wcześniej, należy użyć IntentService do długotrwałego zadania, a następnie nadać z powrotem swoje wyniki. Gdy uruchamiasz usługę, która nie blokuje połączenia, odbiornik transmisji zakończy się w odpowiednim momencie.

AKTUALIZACJA 2 Zgodnie z ekranem this, ekran WYŁ. Nie oznacza, że ​​urządzenie śpi. Masz już rozwiązanie tego problemu za pomocą PowerManager.isScreenOn().

+0

Dzięki za odpowiedź. Ale co z cyklem życia odbiornika? Wiem, że widget jest również odbiornikiem transmisji, ale wydaje się, że klasa rozszerzająca AppWidgetProvider nie może odbierać akcji ACTION_SCREEN_ON/OFF. I niestety, jeśli zarejestruję nowy odbiornik broadcastowy (czyli klasę rozszerzającą BroadcastReceiver), nie jestem pewien co do życia. Zakładam, że to prawda, że ​​Android może zabić każdego BroadcastREceiver, jeśli potrzebuje pamięci ?! – NiThDi

+0

Nie zwracałem uwagi na rzeczy na ekranie. Masz rację, nie można go używać z widżetem. Zaktualizuję moją odpowiedź. – Audrius

0

Podejście ELAPSED_REALTIME może działać, ale dziwnie nie jest to dla małej stworzonej przeze mnie aplikacji testowej. Zasadniczo aplikacja testowa jest widgetem i IntentService. Widżet pokazuje tylko bieżący czas, podczas gdy Intent Service pobiera aktualny czas i wysyła transmisję, którą widżet zużywa w metodzie onReceive() i aktualizuje się. Widżet jest oczywiście zarejestrowanym odbiornikiem dla niestandardowej akcji transmisji. W metodzie onEnabled() w widgecie inicjalizuję alarm dla AlarmManager. Teraz trochę kodu:

Widget onEnabled():

@Override 
public void onEnabled(Context c) { 
    super.onEnabled(c); 

    Intent intent = new Intent(c.getApplicationContext(), SimpleIntentService.class); 

    PendingIntent intentExecuted = PendingIntent.getService(c.getApplicationContext(), 45451894, intent, 
      PendingIntent.FLAG_UPDATE_CURRENT); 

    AlarmManager alarmManager = (AlarmManager) c.getApplicationContext().getSystemService(Context.ALARM_SERVICE); 
    alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 0, 3000, intentExecuted); 
} 

Widget onReceive():

SimpleIntentService onHandleIntent():

@Override 
protected void onHandleIntent(Intent intent) { 
    Log.w("TestService", "SimpleIntentService onHandleIntent called."); 
    String msg = new Date().toGMTString(); 

    Intent broadcastIntent = new Intent(); 
    broadcastIntent.setAction(Widget.ACTION_RESP); 
    broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); 
    broadcastIntent.putExtra("msg", msg); 
    sendBroadcast(broadcastIntent); 
} 

Przetestowałem to na moim Nexusie 4 z Androidem 4.2.1 i emulatorze z Androidem 4.0.4. W obu przypadkach tworzona jest usługa SimpleIntentService, a onHandleIntent() jest wywoływana co 3 sekundy, nawet gdy ręcznie wyłączam wyświetlacz. Nie mam absolutnie pojęcia, dlaczego menedżer alarmów wciąż planuje alarm, czy masz ?!

Dziękujemy!

+0

Zgodnie z [tym] (https://groups.google.com/d/msg/android-developers/Airlo3g5luw/OcLEUW2aq6UJ) wyłączenie ekranu nie oznacza, że ​​urządzenie śpi. Masz już rozwiązanie tego problemu, używając 'PowerManager.isScreenOn()'. – Audrius

Powiązane problemy