Na tej stronie znajdziesz zalecane metody tworzenia bardziej zaawansowanego widżetu, który zapewni użytkownikom większy komfort.
Optymalizacje dotyczące aktualizowania treści widżetu
Aktualizowanie treści widżetu może być kosztowne pod względem obliczeniowym. Aby oszczędzać baterię, zoptymalizuj typ, częstotliwość i czas aktualizacji.
Rodzaje aktualizacji widżetów
Widżet można zaktualizować na 3 sposoby: w całości, częściowo lub (w przypadku widżetu kolekcji) przez odświeżenie danych. Każda z nich ma inne koszty obliczeniowe i konsekwencje.
Poniżej znajdziesz opis każdego typu aktualizacji oraz przykłady kodu.
- Pełna aktualizacja: zadzwoń pod numer
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews), aby w pełni zaktualizować widżet. Zastąpi to wcześniej podany adresRemoteViewsnowym adresemRemoteViews. Jest to najbardziej wymagająca obliczeniowo aktualizacja.
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply { setTextViewText(R.id.textview_widget_layout1, "Updated text1") setTextViewText(R.id.textview_widget_layout2, "Updated text2") } appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
- Aktualizacja częściowa: wywołaj
AppWidgetManager.partiallyUpdateAppWidgetaby zaktualizować części widżetu. Spowoduje to połączenie nowegoRemoteViewsz wcześniej podanymRemoteViews. Ta metoda jest ignorowana, jeśli widżet nie otrzyma co najmniej jednej pełnej aktualizacji za pomocą funkcjiupdateAppWidget(int[], RemoteViews).
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply { setTextViewText(R.id.textview_widget_layout, "Updated text") } appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)
- Odświeżanie danych kolekcji: wywołaj
AppWidgetManager.notifyAppWidgetViewDataChangedaby unieważnić dane widoku kolekcji w widżecie. Spowoduje toRemoteViewsFactory.onDataSetChanged. W tym czasie w widżecie będą wyświetlane stare dane. Dzięki tej metodzie możesz bezpiecznie wykonywać kosztowne zadania synchronicznie.
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Możesz wywoływać te metody z dowolnego miejsca w aplikacji, o ile ma ona ten sam identyfikator UID co odpowiednia klasa AppWidgetProvider.
Określanie częstotliwości aktualizacji widżetu
Widżety są okresowo aktualizowane w zależności od wartości podanej w atrybucie
updatePeriodMillis. Widżet może się aktualizować w odpowiedzi na interakcję użytkownika, emitować aktualizacje lub robić jedno i drugie.
Okresowe aktualizacje
Częstotliwość okresowej aktualizacji możesz kontrolować, podając wartość elementu AppWidgetProviderInfo.updatePeriodMillis w pliku XML appwidget-provider. Każda aktualizacja wywołuje metodę AppWidgetProvider.onUpdate(), w której możesz umieścić kod aktualizujący widżet. Jeśli jednak widżet musi wczytywać dane asynchronicznie lub aktualizacja trwa dłużej niż 10 sekund, rozważ alternatywne sposoby aktualizacji odbiornika transmisji opisane w następnej sekcji, ponieważ po 10 sekundach system uznaje BroadcastReceiver za nieodpowiadający.
updatePeriodMillis nie obsługuje wartości mniejszych niż 30 minut. Jeśli jednak chcesz wyłączyć okresowe aktualizacje, możesz ustawić wartość 0.
Możesz zezwolić użytkownikom na dostosowywanie częstotliwości aktualizacji w konfiguracji. Mogą na przykład chcieć, aby notowania giełdowe były aktualizowane co 15 minut lub tylko 4 razy dziennie. W takim przypadku ustaw wartość updatePeriodMillis na 0 i użyj WorkManager.
Aktualizacja w odpowiedzi na interakcję użytkownika
Oto kilka zalecanych sposobów aktualizowania widżetu na podstawie interakcji użytkownika:
W ramach aktywności aplikacji: bezpośrednio wywołuj
AppWidgetManager.updateAppWidgetw odpowiedzi na interakcję użytkownika, np. kliknięcie.W przypadku interakcji zdalnych, np. powiadomienia lub widżetu aplikacji: utwórz
PendingIntent, a potem zaktualizuj widżet z wywołanegoActivity,BroadcastlubService. Możesz wybrać własny priorytet. Jeśli na przykład wybierzeszBroadcastdlaPendingIntent, możesz wybrać transmisję na pierwszym planie, aby nadać priorytetBroadcastReceiver.
Aktualizacja w odpowiedzi na wydarzenie transmitowane
Przykładem transmitowanego zdarzenia, które wymaga aktualizacji widżetu, jest zrobienie zdjęcia przez użytkownika. W tym przypadku chcesz zaktualizować widżet, gdy zostanie wykryte nowe zdjęcie.
Możesz zaplanować pracę za pomocą WorkManager i określić wyzwalacz URI treści za pomocą metody Constraints.Builder.addContentUriTrigger.
Możesz też zarejestrować BroadcastReceiver na potrzeby transmisji, np. nasłuchiwać ACTION_LOCALE_CHANGED.
Ponieważ jednak zużywa to zasoby urządzenia, korzystaj z tej funkcji ostrożnie i słuchaj tylko konkretnej transmisji. W Androidzie 7.0 (interfejs API na poziomie 24) i Androidzie 8.0 (interfejs API na poziomie 26) wprowadzono ograniczenia dotyczące transmisji, w związku z czym aplikacje nie mogą rejestrować w swoich plikach manifestu transmisji niejawnych, z pewnymi wyjątkami.
Na co zwrócić uwagę podczas aktualizowania widżetu z poziomu BroadcastReceiver
Jeśli widżet jest aktualizowany z BroadcastReceiver, w tym z AppWidgetProvider, pamiętaj o tych kwestiach dotyczących czasu trwania i priorytetu aktualizacji widżetu.
Czas trwania aktualizacji
Z reguły system pozwala odbiornikom transmisji, które zwykle działają w głównym wątku aplikacji, działać do 10 sekund, zanim uzna je za nieodpowiadające i wywoła błąd Aplikacja nie odpowiada (ANR). Aby uniknąć blokowania wątku głównego podczas obsługi transmisji, użyj metody goAsync. Jeśli aktualizacja widżetu trwa dłużej, rozważ zaplanowanie zadania za pomocą WorkManager.
Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.
Więcej informacji znajdziesz w artykule Wskazówki i sprawdzone metody dotyczące bezpieczeństwa.
Priorytet aktualizacji
Domyślnie transmisje, w tym te utworzone za pomocą
AppWidgetProvider.onUpdate, działają jako procesy w tle. Oznacza to, że
przeciążone zasoby systemu mogą spowodować opóźnienie wywołania odbiornika
transmisji. Aby nadać transmisji priorytet, ustaw ją jako proces na pierwszym planie.
Na przykład dodaj flagę Intent.FLAG_RECEIVER_FOREGROUND do parametru Intent przekazywanego do parametru PendingIntent.getBroadcast, gdy użytkownik kliknie określoną część widżetu.