Tworzenie zaawansowanego widżetu

Wypróbuj Compose
Jetpack Compose to zalecany zestaw narzędzi do tworzenia interfejsu na Androidzie. Dowiedz się, jak tworzyć widżety za pomocą interfejsów API w stylu Compose.

Na tej stronie znajdziesz zalecane metody tworzenia bardziej zaawansowanych widżetów, które zapewniają lepsze wrażenia użytkownikom.

Optymalizacja aktualizowania treści widżetu

Aktualizowanie treści widżetu może być kosztowne obliczeniowo. Aby oszczędzać baterię, zoptymalizuj typ, częstotliwość i czas aktualizacji.

Typy aktualizacji widżetu

Widżet można aktualizować na 3 sposoby: pełna aktualizacja, częściowa aktualizacja oraz, w przypadku widżetu kolekcji, odświeżanie danych. Każda z nich ma inne koszty obliczeniowe i konsekwencje.

Poniżej znajdziesz opis każdego typu aktualizacji oraz fragmenty kodu.

  • Pełna aktualizacja: wywołaj AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) aby w pełni zaktualizować widżet. Spowoduje to zastąpienie wcześniej podanych RemoteViews nowymi RemoteViews. Jest to najbardziej kosztowna obliczeniowo aktualizacja.

    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łaj AppWidgetManager.partiallyUpdateAppWidget aby zaktualizować części widżetu. Spowoduje to scalenie nowych RemoteViews z wcześniej podanymi RemoteViews. Ta metoda jest ignorowana, jeśli widżet nie otrzyma co najmniej 1 pełnej aktualizacji 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: wywołaj AppWidgetManager.notifyAppWidgetViewDataChanged aby unieważnić dane widoku kolekcji w widżecie. Spowoduje to wywołanie RemoteViewsFactory.onDataSetChanged. W międzyczasie w widżecie wyświetlane są stare dane. Za pomocą tej metody możesz bezpiecznie wykonywać kosztowne zadania synchronicznie.

    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);

Te metody możesz wywoływać z dowolnego miejsca w aplikacji, o ile ma ona ten sam identyfikator UID co odpowiednia AppWidgetProvider klasa.

Określanie częstotliwości aktualizowania widżetu

Widżety są aktualizowane okresowo w zależności od wartości podanej w updatePeriodMillis atrybucie. Widżet może się aktualizować w odpowiedzi na interakcję użytkownika, aktualizacje transmisji lub obie te rzeczy.

Okresowe aktualizowanie

Częstotliwość okresowej 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 wczytywać dane asynchronicznie lub aktualizacja trwa dłużej niż 10 sekund, rozważ alternatywne metody aktualizacji odbiornika transmisji opisane w następnej sekcji. 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 określić wartość 0.

Możesz pozwolić użytkownikom na dostosowanie 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 updatePeriodMillis na 0 i użyj WorkManager zamiast.

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.updateAppWidget w odpowiedzi na interakcję użytkownika, np. kliknięcie.

  • Z poziomu interakcji zdalnych, np. powiadomienia lub widżetu aplikacji: utwórz PendingIntent, a następnie zaktualizuj widżet z wywołanej Activity, Broadcast lub Service. Możesz wybrać własny priorytet. Jeśli na przykład wybierzesz Broadcast dla PendingIntent, możesz wybrać transmisję na pierwszym planie, aby nadać prioryści BroadcastReceiver.

Aktualizowanie w odpowiedzi na zdarzenie transmisji

Przykładem zdarzenia transmisji, które wymaga aktualizacji widżetu, jest zrobienie zdjęcia przez użytkownika. W takim przypadku chcesz zaktualizować widżet, gdy zostanie wykryte nowe zdjęcie.

Możesz zaplanować zadanie za pomocą JobScheduler i określić transmisję jako wyzwalacz za pomocą JobInfo.Builder.addTriggerContentUri metody.

Możesz też zarejestrować BroadcastReceiver dla transmisji, np. nasłuchiwać ACTION_LOCALE_CHANGED. Ponieważ jednak zużywa to zasoby urządzenia, używaj tej metody ostrożnie i nasłuchuj tylko określonej transmisji. Wraz z wprowadzeniem ograniczeń transmisji w Androidzie 7.0 (poziom interfejsu API 24) i Androidzie 8.0 (poziom interfejsu API 26) 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 poziomu 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 odbiornikom transmisji, które zwykle działają w głównym wątku aplikacji, działać przez maksymalnie 10 sekund, zanim uzna je za nieodpowiadające 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 Sprawy związane z bezpieczeństwem i sprawdzone metody.

Priorytet aktualizacji

Domyślnie transmisje, w tym te wykonywane 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 transmisji. Aby nadać priorytet transmisji, ustaw ją jako proces na pierwszym planie.

Na przykład dodaj flagę Intent.FLAG_RECEIVER_FOREGROUND do Intent przekazywanego do PendingIntent.getBroadcast, gdy użytkownik kliknie określoną część widżetu.