Auf dieser Seite werden Best Practices für die Erstellung eines erweiterten Widgets beschrieben, um die Nutzerfreundlichkeit zu verbessern.
Optimierungen für die Aktualisierung von Widget-Inhalten
Das Aktualisieren von Widget-Inhalten kann rechenintensiv sein. Um den Akku zu schonen Aktualisierungsart, -häufigkeit und -zeitpunkt optimieren.
Arten von Widget-Updates
Es gibt drei Möglichkeiten, ein Widget zu aktualisieren: eine vollständige Aktualisierung, eine teilweise Aktualisierung und bei einem Sammlungs-Widget eine Datenaktualisierung. Jedes hat unterschiedliche Computing-Kosten und Auswirkungen.
Im Folgenden werden die einzelnen Updatetypen beschrieben und es werden Code-Snippets für jeden Typ bereitgestellt.
Vollständiges Update: Rufen Sie
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)
auf, um das Widget vollständig zu aktualisieren. Dies ersetzt das zuvor bereitgestellteRemoteViews
mit einem neuenRemoteViews
. Dies ist die rechenintensivste Aktualisierung.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);
Teilweise Aktualisierung: Anruf
AppWidgetManager.partiallyUpdateAppWidget
um Teile des Widgets zu aktualisieren. Dadurch werden die neuenRemoteViews
und die Zuvor bereitgestelltesRemoteViews
. Diese Methode wird ignoriert, wenn ein Widget erhält nicht mindestens ein vollständiges Update bisupdateAppWidget(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);
Daten einer Sammlung aktualisieren: Rufen Sie
AppWidgetManager.notifyAppWidgetViewDataChanged
auf, um die Daten einer Sammlungsdatenansicht in Ihrem Widget ungültig zu machen. Dadurch wirdRemoteViewsFactory.onDataSetChanged
ausgelöst. In der Zwischenzeit werden die alten Daten im Widget angezeigt. Sie können synchrone Ausführung teurer Aufgaben mit dieser Methode.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);
Sie können diese Methoden von überall in Ihrer App aufrufen, solange die App dieselbe UID wie die entsprechende AppWidgetProvider
-Klasse hat.
Bestimmen, wie oft ein Widget aktualisiert werden soll
Widgets werden regelmäßig aktualisiert, je nachdem, welchen Wert für den
updatePeriodMillis
. Das Widget kann als Reaktion auf Nutzerinteraktionen, als Übertragung von Updates oder beides aktualisiert werden.
Regelmäßig aktualisieren
Sie können die Häufigkeit der regelmäßigen Aktualisierung steuern, indem Sie in der appwidget-provider
-XML einen Wert für AppWidgetProviderInfo.updatePeriodMillis
angeben. Jede Aktualisierung löst die Methode AppWidgetProvider.onUpdate()
aus. Dort können Sie den Code platzieren, um das Widget zu aktualisieren. Berücksichtigen Sie jedoch die Alternativen für Aktualisierungen von Broadcastreceivern, die im folgenden Abschnitt beschrieben werden, wenn Ihr Widget Daten asynchron laden muss oder die Aktualisierung mehr als 10 Sekunden dauert. Nach 10 Sekunden betrachtet das System eine BroadcastReceiver
als nicht reagierend.
updatePeriodMillis
unterstützt keine Werte unter 30 Minuten. Wenn Sie jedoch regelmäßige Updates deaktivieren möchten, können Sie „0“ angeben.
Sie können Nutzern erlauben, die Häufigkeit von Aktualisierungen in einer Konfiguration anzupassen. Für
Sie möchten vielleicht, dass ein Börsenticker alle 15 Minuten oder nur 4 Minuten aktualisiert wird.
-mal pro Tag. Setzen Sie in diesem Fall updatePeriodMillis
auf 0 und verwenden Sie
WorkManager
.
Aktualisierung als Reaktion auf eine Nutzerinteraktion
Hier sind einige empfohlene Möglichkeiten, das Widget basierend auf Nutzerinteraktionen zu aktualisieren:
Über eine Aktivität der App:direkt anrufen
AppWidgetManager.updateAppWidget
als Reaktion auf eine Nutzerinteraktion, z. B. wie beim Tippen der Nutzenden.Über Remote-Interaktionen wie Benachrichtigungen oder App-Widgets: Erstelle eine
PendingIntent
und aktualisiere das Widget dann über die aufgerufeneActivity
,Broadcast
oderService
. Sie können Ihre eigene Priorität festlegen. Wenn Sie beispielsweise eineBroadcast
für diePendingIntent
auswählen, können Sie eine Auslieferung im Vordergrund auswählen, um derBroadcastReceiver
Priorität zu geben.
Aktualisierung als Reaktion auf ein Übertragungsereignis
Ein Beispiel für ein Übertragungsereignis, für das ein Widget aktualisiert werden muss, ist der Zeitpunkt, der Nutzer ein Foto aufnimmt. In diesem Fall möchten Sie das Widget aktualisieren, wenn ein neues Foto erkannt wird.
Sie können einen Job mit JobScheduler
planen und mit der Methode JobInfo.Builder.addTriggerContentUri
einen Broadcast als Trigger angeben.
Sie können auch ein BroadcastReceiver
für die Übertragung registrieren, z. B.:
zuhören auf
ACTION_LOCALE_CHANGED
Da dies jedoch Geräteressourcen beansprucht, solltest du diese Funktion mit Bedacht verwenden und nur die gewünschte Übertragung abspielen. Mit der Einführung von Einschränkungen für Broadcasts in Android 7.0 (API-Level 24) und Android 8.0 (API-Level 26) können Apps mit bestimmten Ausnahmen keine impliziten Broadcasts mehr in ihren Manifesten registrieren.
Hinweise zum Aktualisieren eines Widgets über einen BroadcastReceiver
Wenn das Widget über eine BroadcastReceiver
-Version aktualisiert wird, einschließlich AppWidgetProvider
, beachten Sie die folgenden Hinweise zur Dauer und Priorität eines Widget-Updates.
Dauer der Aktualisierung
Normalerweise lässt das System Broadcast-Empfänger, die normalerweise im Haupt-Thread der App ausgeführt werden, bis zu 10 Sekunden lang laufen, bevor sie als nicht reagierend eingestuft und ein ANR-Fehler (Application Not Responding, Anwendung reagiert nicht) ausgelöst wird. Wenn das Aktualisieren des Widgets länger dauert, haben Sie folgende Möglichkeiten:
Aufgaben mit
WorkManager
planenMit der Methode
goAsync
kannst du dem Empfänger mehr Zeit geben. Dadurch wird die Ausführung durch Empfänger 30 Sekunden lang ermöglicht.
Weitere Informationen finden Sie unter Sicherheitsaspekte und Best Practices.
Priorität des Updates
Standardmäßig werden Übertragungen – einschließlich solcher, die per
AppWidgetProvider.onUpdate
– als Hintergrundprozesse ausführen Das bedeutet,
Überlastete Systemressourcen können zu einer Verzögerung beim Aufruf der Übertragung führen.
Empfänger. Wenn du die Übertragung priorisieren möchtest, solltest du sie als Vordergrundprozess festlegen.
Fügen Sie beispielsweise das Flag Intent.FLAG_RECEIVER_FOREGROUND
dem Intent
hinzu, das an die PendingIntent.getBroadcast
übergeben wird, wenn der Nutzer auf einen bestimmten Teil des Widgets tippt.
Genaue Vorschauen mit dynamischen Elementen erstellen
In diesem Abschnitt wird die empfohlene Vorgehensweise für die Anzeige mehrerer Elemente in
Widget-Vorschau für ein Widget mit einer Sammlung
-Ansicht, d. h. ein Widget, das
ListView
, GridView
oder StackView
.
Wenn für Ihr Widget eine dieser Ansichten verwendet wird, ist die Nutzerfreundlichkeit eingeschränkt, wenn Sie eine skalierbare Vorschau erstellen, indem Sie direkt das tatsächliche Widget-Layout angeben, und in der Widget-Vorschau keine Elemente angezeigt werden. Das liegt daran, dass Daten in Sammlungsansichten während der Laufzeit dynamisch festgelegt werden. Sie sehen in etwa so aus wie in Abbildung 1.
Damit eine Vorschau von Widgets mit Sammlungsansichten ordnungsgemäß im Widget angezeigt wird
-Auswahl empfehlen wir, eine separate Layoutdatei zu erstellen, die nur für den
in der Vorschau ansehen. Diese separate Layoutdatei enthält das Widget-Layout und ein
Platzhaltersammlungsansicht mit gefälschten Elementen. Sie können beispielsweise einen
ListView
durch Angabe des Platzhalters LinearLayout
mit mehreren gefälschten Listen
Elemente.
Um ein Beispiel für ein ListView
zu veranschaulichen, beginnen Sie mit einer separaten Layoutdatei:
// 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>
Geben Sie die Vorschau-Layoutdatei an, wenn Sie das previewLayout
-Attribut der AppWidgetProviderInfo
-Metadaten angeben. Sie geben weiterhin das tatsächliche Widget-Layout für das initialLayout
-Attribut an und verwenden es beim Erstellen eines RemoteViews
zur Laufzeit.
<appwidget-provider
previewLayout="@layout/widget_previe"
initialLayout="@layout/widget_view" />
Komplexe Listenelemente
Das Beispiel im vorherigen Abschnitt enthält gefälschte Listenelemente, da die Liste
Elemente sind TextView
-Objekte. Es kann schwieriger sein, gefälschte Artikel bereitzustellen, wenn es sich um komplexe Layouts handelt.
Nehmen wir ein Listenelement, das in widget_list_item.xml
definiert ist und aus folgenden Elementen besteht:
Zwei TextView
-Objekte:
<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>
Um gefälschte Listenelemente bereitzustellen, können Sie das Layout mehrmals einfügen. führt dazu, dass jedes Listenelement identisch ist. Um eindeutige Listenelemente bereitzustellen, folgen Sie diese Schritte:
Erstellen Sie eine Reihe von Attributen für die Textwerte:
<resources> <attr name="widgetTitle" format="string" /> <attr name="widgetContent" format="string" /> </resources>
Verwenden Sie diese Attribute, um den Text festzulegen:
<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>
Erstellen Sie so viele Stile, wie für die Vorschau erforderlich sind. Definieren Sie die Werte in für jeden Stil:
<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>
Wenden Sie die Stile auf die gefälschten Elemente im Vorschaulayout an:
<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>