Tworzenie zaawansowanego widżetu

Na tej stronie opisujemy zalecane metody tworzenia bardziej zaawansowanych widżetów dla i lepsze wrażenia użytkowników.

Optymalizacje w zakresie aktualizowania zawartości widżetów

Aktualizowanie zawartości widżetu może być kosztowne pod względem obliczeń. Aby oszczędzać baterię zoptymalizować typ, częstotliwość i czas aktualizacji.

Rodzaje aktualizacji widżetów

Widżet można zaktualizować na 3 sposoby: pełną aktualizację, aktualizację częściową lub w przypadku widżetu kolekcji – odświeżenie danych. Każdy z nich ma inny koszty obliczeniowe i ich konsekwencje.

Poniżej opisujemy poszczególne typy aktualizacji i przedstawiamy fragmenty kodu dla każdego z nich.

  • Pełna aktualizacja: zadzwoń pod numer AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) aby w pełni zaktualizować widżet. Spowoduje to zastąpienie poprzednio podanej wartości RemoteViews z nowym 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: połączenie AppWidgetManager.partiallyUpdateAppWidget. aby zaktualizować 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 jednej pełnej aktualizacji do 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 aktualizowania widżetu

Widżety są aktualizowane okresowo w zależności od wartości atrybutu updatePeriodMillis . Widżet może się aktualizować w odpowiedzi na interakcje użytkownika, komunikaty lub jedno i drugie.

Aktualizuj okresowo

Można kontrolować częstotliwość aktualizacji okresowych, określając wartość dla AppWidgetProviderInfo.updatePeriodMillis w pliku XML appwidget-provider. Każdy aktualizacja powoduje uruchomienie metody 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 dostosowywanie częstotliwości aktualizacji w 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 w zależności od 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 poziomu interakcji zdalnych, takich jak powiadomienia lub widżet aplikacji: utwórz PendingIntent, a następnie zaktualizuj widżet z 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. Pozwala to aktualizować widżet, gdy 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ą funkcji WorkManager.

  • Daj odbiorcy więcej czasu, goAsync. Dzięki temu odbiorcy będą wykonywać 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 systemowe mogą powodować opóźnienie wywołania transmisji odbiorcy. Aby nadać transmisji priorytetową, ustaw ją jako proces na pierwszym planie.

Na przykład dodaj parametr Intent.FLAG_RECEIVER_FOREGROUND flaga do Intent przekazywanej do PendingIntent.getBroadcast, gdy użytkownik i kliknie określoną część 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 działania i wyglądają podobnie do na ilustracji 1.

Aby podglądy widżetów z widokami kolekcji były prawidłowo wyświetlane w widżecie zalecamy zachowanie osobnego pliku układu przeznaczonego tylko na podgląd. Ten oddzielny plik układu zawiera rzeczywisty układ widżetu oraz element zastępczy widok kolekcji z fałszywymi elementami. Możesz na przykład udawać ListView, podając obiekt zastępczy LinearLayout z kilkoma fałszywymi listami elementy(ów).

Aby pokazać przykład dla elementu 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>

Określ plik układu podglądu, podając atrybut previewLayout metadane AppWidgetProviderInfo. Nadal określasz rzeczywisty układ widżetu dla atrybutu initialLayout i używać rzeczywistego układu widżetu, gdy podczas tworzenia obiektu RemoteViews w czasie działania.

<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ż elementy to TextView. Jest taka możliwość dostarczanie fałszywych przedmiotów jest bardziej złożone, jeśli elementy mają złożone układy.

Zastanów się nad elementem listy zdefiniowanym w zasadzie widget_list_item.xml i składanym z tych elementów: dwa obiekty 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 pozycje listy, możesz dodać układ kilka razy, ale w tym przypadku sprawi, że elementy listy będą identyczne. Aby podać unikalne elementy listy, postępuj zgodnie z 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. Użyj tych atrybutów, aby ustawić tekst:

    <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 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. Zastosuj style 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>