Na tej stronie znajdziesz zalecane metody tworzenia bardziej zaawansowanego widżetu, który zapewni użytkownikom lepsze wrażenia.
Optymalizacje pod kątem 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: pełna aktualizacja, częściowa aktualizacja oraz, w przypadku widżetu kolekcji, odświeżenie danych. Każda z nich ma inne koszty obliczeniowe i konsekwencje.
Poniżej opisujemy każdy typ aktualizacji i podajemy fragmenty kodu.
- Pełna aktualizacja: wywołaj
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews), aby w pełni zaktualizować widżet. Spowoduje to zastąpienie podanego wcześniejRemoteViewsnowymRemoteViews. 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)
- Częściowa aktualizacja: wywołaj
AppWidgetManager.partiallyUpdateAppWidget, aby zaktualizować części widżetu. Spowoduje to scalenie nowego elementuRemoteViewsz wcześniej podanym elementemRemoteViews. Ta metoda jest ignorowana, jeśli widżet nie otrzyma co najmniej 1 pełnej aktualizacji przezupdateAppWidget(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.notifyAppWidgetViewDataChanged, aby unieważnić dane widoku kolekcji w widżecie. Spowoduje to uruchomienieRemoteViewsFactory.onDataSetChanged. W tym czasie w widżecie wyświetlane są stare dane. Za pomocą tej metody możesz bezpiecznie wykonywać kosztowne zadania synchronicznie.
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Te metody możesz wywoływać z dowolnego miejsca w aplikacji, o ile aplikacja ma ten sam identyfikator UID co odpowiednia klasa AppWidgetProvider.
Określanie częstotliwości aktualizowania 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, aktualizacje transmisji lub obie te sytuacje.
Aktualizuj okresowo
Częstotliwość okresowych aktualizacji możesz kontrolować, określając wartość 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 ładować dane asynchronicznie lub aktualizacja trwa dłużej niż 10 sekund, rozważ alternatywne rozwiązania dotyczące aktualizacji odbiornika komunikatów opisane w następnej sekcji, ponieważ po 10 sekundach system uznaje, że BroadcastReceiver nie odpowiada.
updatePeriodMillis nie obsługuje wartości mniejszych niż 30 minut. Jeśli jednak chcesz wyłączyć okresowe aktualizacje, możesz podać 0.
Możesz zezwolić użytkownikom na dostosowywanie częstotliwości aktualizacji w konfiguracji. Na przykład mogą chcieć, aby pasek giełdowy był aktualizowany co 15 minut lub tylko 4 razy dziennie. W takim przypadku ustaw parametr updatePeriodMillis na 0 i użyj parametru WorkManager.
Aktualizowanie w odpowiedzi na interakcję użytkownika
Oto kilka zalecanych sposobów aktualizowania widżetu na podstawie interakcji użytkownika:
Z poziomu aktywności aplikacji: wywołaj bezpośrednio
AppWidgetManager.updateAppWidgetw odpowiedzi na interakcję użytkownika, np. kliknięcie.Z interakcji zdalnych, takich jak powiadomienie lub widżet aplikacji: utwórz obiekt
PendingIntent, a następnie zaktualizuj widżet z wywołanego obiektuActivity,BroadcastlubService. Możesz wybrać własny priorytet. Jeśli na przykład wybierzeszBroadcastdlaPendingIntent, możesz wybrać transmisję na pierwszym planie, aby nadać priorytetBroadcastReceiver.
Aktualizowanie w odpowiedzi na zdarzenie rozgłaszania
Przykładem 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ć zadanie za pomocą WorkManager i określić aktywator identyfikatora URI treści za pomocą metody Constraints.Builder.addContentUriTrigger.
Możesz też zarejestrować BroadcastReceiver dla transmisji, na przykład nasłuchując ACTION_LOCALE_CHANGED.
Ponieważ jednak zużywa to zasoby urządzenia, używaj tej funkcji ostrożnie i nasłuchuj tylko określonej transmisji. Wraz z wprowadzeniem ograniczeń dotyczących komunikatów w Androidzie 7.0 (poziom interfejsu API 24) i Androidzie 8.0 (poziom interfejsu API 26) aplikacje nie mogą rejestrować komunikatów ogólnych w swoich plikach manifestu, z pewnymi wyjątkami.
Uwagi dotyczące aktualizowania widżetu z BroadcastReceiver
Jeśli widżet jest aktualizowany z BroadcastReceiver, w tym AppWidgetProvider, pamiętaj o tych kwestiach dotyczących czasu trwania i priorytetu aktualizacji widżetu.
Czas trwania aktualizacji
Z reguły system pozwala odbiorcom komunikatów, którzy zwykle działają w głównym wątku aplikacji, na działanie przez maksymalnie 10 sekund, zanim uzna, że nie odpowiadają, i wywoła błąd Aplikacja nie odpowiada (ANR). Aby uniknąć blokowania głównego wątku 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 Kwestie bezpieczeństwa i sprawdzone metody.
Priorytet aktualizacji
Domyślnie transmisje, w tym te realizowane za pomocą AppWidgetProvider.onUpdate, działają jako procesy w tle. Oznacza to, że przeciążone zasoby systemowe mogą spowodować opóźnienie w wywołaniu odbiornika komunikatów. Aby nadać transmisji priorytet, ustaw ją jako proces na pierwszym planie.
Możesz na przykład dodać flagę Intent.FLAG_RECEIVER_FOREGROUND do obiektu Intent przekazywanego do metody PendingIntent.getBroadcast, gdy użytkownik kliknie określoną część widżetu.