Tworzenie zaawansowanego widżetu

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 pliku RemoteViews nowym plikiem RemoteViews. 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 nowej RemoteViews z podany wcześniej RemoteViews. 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 wyzwala RemoteViewsFactory.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łanego Activity, Broadcast lub Service. Możesz wybrać własny priorytet. Dla: np. jeśli wybierzesz Broadcast dla elementu PendingIntent, 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

Rys. 1. Podgląd widżetu bez elementów listy.

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:

  1. Utwórz zestaw atrybutów dla wartości tekstowych:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. 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>
    
  3. 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>
    
  4. 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>