2010-03-10 10 views
27

Mam zamiar utworzyć widget, który musi aktualizować swoją zawartość co minutę (pokazuje dane związane z czasem).Android - jak często aktualizować widżet, ale tylko wtedy, gdy jest widoczny?

Jednakże, nie ma potrzeby, aby zaktualizować widget jeśli jest obecnie niewidoczny, co oznacza:

  • ekran jest wyłączony
  • inna aplikacja jest uruchomiona
  • widget jest umieszczony na innym (niewidoczny) karta ekranu głównego

Jaki jest najlepszy sposób aktualizowania tylko widocznego widżetu co minutę - bez budzenia urządzenia i wykonywania niepotrzebnych obliczeń? Widżet staje się widoczny, małe opóźnienie przed aktualizacją jest dopuszczalne.

Odpowiedz

15

Aby nie aktualizować, gdy ekran jest wyłączony, użyj AlarmManager, aby zaplanować alarm cykliczny, który nie budzi telefonu.

Dwa pozostałe punkty w pytaniu nie są możliwe. Nie ma możliwości wykrycia, czy widget znajduje się na ekranie głównym, który nie jest obecnie widoczny, i nie można ustalić, czy działa aplikacja, która ukrywa ekran główny. Złożyłem zgłoszenie na numer http://b.android.com, prosząc o dodanie tej funkcji do systemu Android. Jeśli masz ochotę zagrać w nim, pomożesz mu uzyskać pierwszeństwo: http://code.google.com/p/android/issues/detail?id=5529&q=reporter:mark.r.baird&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

+0

Zagrałem, przynajmniej to mogę zrobić, odpowiedziałeś na wiele moich pytań i prawdopodobnie zrobię to w przyszłości. Dzięki. – Pentium10

+0

Oznaczona gwiazdką, szkoda, nie będzie dostępna w milionach obecnie używanych widełek ... – tomash

+1

Możliwe jest określenie, która aplikacja jest aktualnie uruchomiona: ActivityManager mAM = (ActivityManager) context.getSystemService (Context.ACTIVITY_SERVICE); Lista tasks = mAM.getRunningTasks (1); – Niels

6

Znalazłem to pod projektem o nazwie 24clock in goole code. Próbuje Nie aktualizować widżetu, gdy użytkownik jest poza domem:

ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 

    List<RunningTaskInfo> runningTasks = am.getRunningTasks(2); 
    for (RunningTaskInfo t : runningTasks) { 
     if (t != null && t.numRunning > 0) { 
      ComponentName cn = t.baseActivity; 
      if (cn == null) continue; 

      String clz = cn.getClassName(); 
      String pkg = cn.getPackageName(); 

      // TODO make this configurable 
      if (pkg != null && pkg.startsWith("com.android.launcher")) { 
       return true; 
      } 

      return false; 
     } 
    } 

To może być odpowiedź dla ciebie wymaganie nr 2. Chociaż może nie działać pod innymi wyrzutnie 3rd party.

== Aktualizacja ==

Kilka miesięcy później, nagle mieć pomysł w mojej głowie na temat sposobu wykrywania, czy ekran główny pokazuje. Umieściłem go w moim blog, a ja przeprowadziłem test na moim pożądaniu i działa dobrze. Metoda polega na wysłaniu zapytania do systemu Android o wszystkie zainstalowane pakiety, z których jedna zawiera funkcję "Launcher", a następnie sprawdź, czy znajduje się na szczycie stosu. Jeśli ktokolwiek przetestował, daj mi znać również wynik, ponieważ nie mam dostępu do innych urządzeń z Androidem.

+2

Z pewnością to się nie powiedzie strasznie, gdy biegasz na niestandardowym ekranie głównym? – Adrian

+2

Proszę zobaczyć moją zaktualizowaną odpowiedź, mam lepszą metodę, która powinna działać w 3rd party. – xandy

+0

uwaga: wymaga pozwolenia GET_TASKS – larham1

8
  1. Można poprosić PowerManager o isScreenOn()
  2. Możesz się zarejestrować za Intent ACTION_SCREEN_OFF/ACTION_SCREEN_ON i włączyć się TIMER ON/OFF odpowiednio.

Mimo że powyższa odpowiedź dotycząca AlarmManagera jest poprawna, może to nie wystarczyć, ponieważ zaobserwowałem, że wiele telefonów również wysyła alarmy, nawet jeśli nie są one typu * _WAKEUP. Może się tak zdarzyć, jeśli zainstalowane są inne aplikacje, które budzą urządzenie. A jeśli już się obudził, dostarcza wszystkie oczekujące alarmy.

+0

To bardzo ważna kwestia.Alarm może się uruchomić, nawet jeśli ekran śpi, jak wyjaśniono w [tym wątku] (https://groups.google.com/forum/?fromgroups=#!topic/android-developers/Airlo3g5luw). – lseidman

+0

Zauważyłem również, że przy włączonym trybie programisty (i rejestrowaniu zawartości do logcat) urządzenie nie śpi. Aby przetestować, co zrobiłby on bez trybu deweloperskiego, dodałem licznik wszystkich aktualizacji do wyświetlenia na widżecie i zauważyłem, że przy wyłączonym trybie programisty przejdzie on w tryb uśpienia i nie zaktualizuje widgetu zdarzeniami AlarmManager.RTC. Nie mogę znaleźć żadnej dokumentacji, która sprawiłaby, że tryb programisty nie pozwala jej zasnąć, ale ma dla mnie sens. –

0

Przyjęta odpowiedź od mbaird trafia w gwóźdź w głowę. Proponowana metoda onVisivilityChange(), jeśli zaimplementowana, powinna obejmować wszystkie powyższe przypadki.

W międzyczasie jest to nadal poważny problem dla niektórych typów widżetów. jom wprowadził możliwość rejestracji, aby otrzymać intencje ACTION_SCREEN_OFF/ACTION_SCREEN_ON.Jest to użyteczne, ponieważ poleganie na powtarzającym się alarmie nie jest wystarczające, ponieważ inne usługi powodują pobudki. Jest to trudne, ponieważ takich działań nie można zasubskrybować za pośrednictwem AndroidManifest.xml, a AppWidgetProvider nie może wywoływać numeru context.registerReceiver(). Kwestie te omówiono w kilku innych pytaniach dotyczących StackOverflow, w tym Listening for ACTION_SCREEN_OFF, android.intent.action.SCREEN_ON doesn't work as a receiver intent filter i Android - how to receive broadcast intents ACTION_SCREEN_ON/OFF?.

udało mi się subskrybowania ACTION_SCREEN_OFF zamiarów/ACTION_SCREEN_ON w widgecie poprzez stworzenie uzupełniającej BroascastReceiver instancji i korzystania context.getApplicationContext().registerReceiver() aby go zarejestrować. To może być oszustwo i przynajmniej w niektórych kolejnych wersjach Androida może się nie udać na etapie rejestracji lub może po prostu zdarzenia nie zostaną dostarczone. Zakodowałem do obsługi tych przypadków, ale na razie to działa. Niestety, to nie zadziała, jeśli i kiedykolwiek aplikacja zostanie zabita.

Inną możliwością jest użycie metody typu isHomeScreenShowing(), zgodnie z opisem here, do której odwołuje się odpowiedź Xandy'ego. Pomysły, które tam prawdopodobnie mogłyby zostać zoptymalizowane przez buforowanie wygenerowanej listy zainstalowanych aplikacji CATEGORY_HOME i słuchanie transmisji ACTION_PACKAGE_ADDED/ZMIENIONYCH/USUWANYCH w celu aktualizacji.

Moja strategia jest:

  • Spróbuj uniknąć nazywa (poprzez powtarzalny alarm), gdy nie jest widoczny.
  • Po wywołaniu sprawdź stan ekranu i inne wskaźniki widoczności, zanim zrobisz cokolwiek kosztownego.
  • Następnie należy wywołać IntentService w celu obsługi stosunkowo kosztownej pracy, która obejmuje trwałe połączenie sieciowe. Jest to konieczne do monitorowania stanu usługi zdalnej w czasie zbliżonym do rzeczywistego.
Powiązane problemy