Na tej stronie znajdziesz informacje o sprawdzonych metodach tworzenia bardziej zaawansowanego widżetu, który zapewni użytkownikom lepsze wrażenia.
Optymalizacje w zakresie aktualizowania zawartości widżetów
Aktualizowanie treści widżetu może być kosztowne pod względem zasobów obliczeniowych. 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 pełni, częściowo lub, w przypadku widżetu kolekcji, odświeżyć dane. Każdy z nich wiąże się z różnymi kosztami i konsekwencjami obliczeniowymi.
Poniżej opisujemy poszczególne typy aktualizacji i zamieszczamy odpowiednie fragmenty kodu.
Pełna aktualizacja: wywołaj funkcję
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)
, aby w pełni zaktualizować widżet. Spowoduje to zastąpienie wcześniej przesłanego plikuRemoteViews
nowym plikiemRemoteViews
. To najdroższa aktualizacja pod względem obliczeń.Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also { setTextViewText(R.id.textview_widget_layout1, "Updated text1") setTextViewText(R.id.textview_widget_layout2, "Updated text2") } appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout); remoteViews.setTextViewText(R.id.textview_widget_layout1, "Updated text1"); remoteViews.setTextViewText(R.id.textview_widget_layout2, "Updated text2"); appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
Częściowa aktualizacja: wywołanie
AppWidgetManager.partiallyUpdateAppWidget
służy do aktualizowania części widżetu. Spowoduje to scalenie nowejRemoteViews
z podany wcześniejRemoteViews
. Ta metoda jest ignorowana, jeśli widżet nie otrzyma co najmniej 1 pełnego uaktualnienia za pomocąupdateAppWidget(int[], RemoteViews)
.Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also { setTextViewText(R.id.textview_widget_layout, "Updated text") } appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout); remoteViews.setTextViewText(R.id.textview_widget_layout, "Updated text"); appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews);
Odświeżanie danych kolekcji: połączenie
AppWidgetManager.notifyAppWidgetViewDataChanged
, aby unieważnić dane widoku kolekcji w widżecie. To wyzwalaRemoteViewsFactory.onDataSetChanged
Do tego czasu w widżecie wyświetlane są stare dane. Możesz bezpiecznie synchronicznie z wykorzystaniem tej metody do wykonywania kosztownych zadań.Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview);
Możesz wywoływać te metody z dowolnego miejsca w aplikacji, jeśli tylko aplikacja ma
taki sam identyfikator UID jak odpowiedni identyfikator
AppWidgetProvider
.
Określanie częstotliwości odświeżania widżetu
Widgety są okresowo aktualizowane w zależności od wartości podanej dla atrybutu updatePeriodMillis
. Widżet może się aktualizować w odpowiedzi na interakcje użytkownika, komunikaty
lub jedno i drugie.
Aktualizuj okresowo
Częstotliwość okresowych aktualizacji możesz kontrolować, określając wartość elementu AppWidgetProviderInfo.updatePeriodMillis
w pliku XML appwidget-provider
. Każdy
aktualizacja uruchamia metodę AppWidgetProvider.onUpdate()
, w której
aby zaktualizować widżet. Rozważ jednak alternatywy dla
aktualizacje odbiornika opisane w
tej sekcji, jeśli widżet musi ładować dane asynchronicznie lub pobierać więcej
trwa dłużej niż 10 sekund, ponieważ po 10 sekundach system uznaje
BroadcastReceiver
, aby nie odpowiadał.
updatePeriodMillis
nie obsługuje wartości krótszych niż 30 minut. Jeśli jednak
Jeśli chcesz wyłączyć okresowe aktualizacje, możesz wpisać 0.
Możesz zezwolić użytkownikom na zmianę częstotliwości aktualizacji w ramach konfiguracji. Dla:
Na przykład mogą chcieć, aby pasek giełdowy aktualizował się co 15 minut lub tylko co 4 minuty.
razy dziennie. W tym przypadku ustaw updatePeriodMillis
na 0 i użyj wartości
WorkManager
.
Aktualizacja w odpowiedzi na interakcję użytkownika
Oto kilka zalecanych sposobów aktualizowania widżetu na podstawie interakcji użytkownika:
Z poziomu aktywności w aplikacji: zadzwoń bezpośrednio
AppWidgetManager.updateAppWidget
w odpowiedzi na interakcję użytkownika, taką jak kliknij go.Z dalszych interakcji, takich jak powiadomienie lub widżet aplikacji: utwórz
PendingIntent
, a następnie zaktualizuj widżet z wywołanegoActivity
,Broadcast
lubService
. Możesz wybrać własny priorytet. Dla: np. jeśli wybierzeszBroadcast
dla elementuPendingIntent
, możesz wybrać komunikat na pierwszym planie, który przekaże Priorytet:BroadcastReceiver
.
Aktualizacja w odpowiedzi na transmitowane wydarzenie
Przykładem transmitowanego wydarzenia, które wymaga aktualizacji widżetu, jest sytuacja, w której robi zdjęcie. W tym przypadku chcesz zaktualizować widget, gdy zostanie wykryte nowe zdjęcie.
Możesz zaplanować zadanie za pomocą funkcji JobScheduler
i określić transmisję jako
za pomocą funkcji
JobInfo.Builder.addTriggerContentUri
.
Możesz też zarejestrować BroadcastReceiver
dla transmisji, na przykład
nasłuchuję
ACTION_LOCALE_CHANGED
Jednak zużywanie zasobów urządzenia jest wykorzystywane, dlatego zachowaj ostrożność i słuchaj
tylko do konkretnej transmisji. Dzięki wprowadzeniu transmisji na żywo
ograniczenia na Androidzie
7.0 (poziom interfejsu API 24) i Android 8.0 (poziom interfejsu API 26) nie można domyślnie rejestrować aplikacji
komunikatów w plikach manifestu, z uwzględnieniem pewnych
wyjątkami.
Uwagi na temat aktualizowania widżetu z BroadcastReceiver
Jeśli widżet jest aktualizowany z elementu BroadcastReceiver
, w tym
AppWidgetProvider
, pamiętaj o następujących kwestiach związanych z
czasu trwania i priorytetu aktualizacji widżetu.
Czas trwania aktualizacji
System zazwyczaj dopuszcza odbiorniki, które zwykle działają na poziomie w wątku głównym, należy uruchomić go przez maksymalnie 10 sekund, zanim uznamy, że nie odpowiada uruchomienie polecenia Application Not Reagowanie na błąd (ANR). Jeśli potrwa to dłużej, zaktualizuj widżet, rozważ inne alternatywne rozwiązania:
Zaplanuj zadanie za pomocą
WorkManager
.Daj odbiorcy więcej czasu, korzystając z metody
goAsync
. Dzięki temu odbiorcy mogą wykonywać operacje przez 30 sekund.
Zobacz Uwagi na temat bezpieczeństwa i najważniejsze informacje sprawdzone metody, i informacjami o nich.
Priorytet aktualizacji
Domyślnie komunikaty, w tym te przeprowadzone za pomocą
AppWidgetProvider.onUpdate
– jest uruchamiany jako procesy w tle. Oznacza to, że przeciążone zasoby systemu mogą spowodować opóźnienie wywołania odbiornika transmisji. Aby nadawanie miało priorytet, ustaw je jako proces na pierwszym planie.
Możesz na przykład dodać do parametru Intent
przekazywanego do parametru PendingIntent.getBroadcast
flagę Intent.FLAG_RECEIVER_FOREGROUND
, która jest wywoływana, gdy użytkownik kliknie określony element widżetu.
Tworzenie dokładnych podglądów z uwzględnieniem elementów dynamicznych
W tej sekcji opisujemy zalecane metody wyświetlania wielu elementów w
podgląd widżetu z kolekcją
– czyli widżet, który korzysta z tagu
ListView
, GridView
lub StackView
.
Jeśli widżet korzysta z jednego z tych widoków, utworzenie skalowalnego podglądu bezpośrednio udostępniam rzeczywisty widżet układ pogarsza gdy na podglądzie widżetu nie ma żadnych elementów. Dzieje się tak, ponieważ dane widoku kolekcji są ustawiane dynamicznie w czasie wykonywania programu i wyglądają podobnie do obrazu przedstawionego na rysunku 1.
Aby w selektorze widżetów prawidłowo wyświetlały się podglądy widżetów z widokami kolekcji, zalecamy utrzymanie osobnego pliku układu przeznaczonego tylko do podglądu. Ten oddzielny plik układu zawiera rzeczywisty układ widżetu i widok kolekcji z obiektami zastępczymi. Możesz na przykład zasymulować obiekt ListView
, podając obiekt zastępczy LinearLayout
z kilkoma fałszywymi elementami listy.
Aby zilustrować przykład ListView
, zacznij od osobnego pliku układu:
// res/layout/widget_preview.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/widget_background"
android:orientation="vertical">
// Include the actual widget layout that contains ListView.
<include
layout="@layout/widget_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
// The number of fake items you include depends on the values you provide
// for minHeight or targetCellHeight in the AppWidgetProviderInfo
// definition.
<TextView android:text="@string/fake_item1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="?attr/appWidgetInternalPadding" />
<TextView android:text="@string/fake_item2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="?attr/appWidgetInternalPadding" />
</LinearLayout>
Podczas podawania atrybutu previewLayout
w metadanych AppWidgetProviderInfo
określ plik układu podglądu. Nadal określasz rzeczywisty układ widżetu dla atrybutu initialLayout
i używasz rzeczywistego układu widżetu podczas tworzenia elementu RemoteViews
w czasie wykonywania.
<appwidget-provider
previewLayout="@layout/widget_previe"
initialLayout="@layout/widget_view" />
Złożone elementy listy
Przykład w poprzedniej sekcji zawiera fałszywe elementy listy, ponieważ są to obiekty TextView
. Podanie fałszywych elementów może być trudniejsze, jeśli są to złożone układy.
Weź pod uwagę element listy zdefiniowany w elementach widget_list_item.xml
, który składa się z 2 obiektów TextView
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/fake_title" />
<TextView android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/fake_content" />
</LinearLayout>
Aby podać fałszywe elementy listy, możesz użyć układu kilka razy, ale spowoduje to, że wszystkie elementy będą identyczne. Aby przesłać unikalne elementy listy, wykonaj te czynności:
Utwórz zestaw atrybutów dla wartości tekstowych:
<resources> <attr name="widgetTitle" format="string" /> <attr name="widgetContent" format="string" /> </resources>
Aby ustawić tekst, użyj tych atrybutów:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="?widgetTitle" /> <TextView android:id="@id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="?widgetContent" /> </LinearLayout>
Utwórz dowolną liczbę stylów do podglądu. Zdefiniuj ponownie wartości w każdym stylu:
<resources> <style name="Theme.Widget.ListItem"> <item name="widgetTitle"></item> <item name="widgetContent"></item> </style> <style name="Theme.Widget.ListItem.Preview1"> <item name="widgetTitle">Fake Title 1</item> <item name="widgetContent">Fake content 1</item> </style> <style name="Theme.Widget.ListItem.Preview2"> <item name="widgetTitle">Fake title 2</item> <item name="widgetContent">Fake content 2</item> </style> </resources>
Zastosowanie stylów do fałszywych elementów w układzie podglądu:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" ...> <include layout="@layout/widget_view" ... /> <include layout="@layout/widget_list_item" android:theme="@style/Theme.Widget.ListItem.Preview1" /> <include layout="@layout/widget_list_item" android:theme="@style/Theme.Widget.ListItem.Preview2" /> </LinearLayout>