Erweitertes Widget erstellen

Jetpack Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Erstellen von Widgets mit Compose-APIs

Auf dieser Seite werden empfohlene Vorgehensweisen zum Erstellen eines erweiterten Widgets für eine bessere Nutzererfahrung erläutert.

Optimierungen für das Aktualisieren von Widget-Inhalten

Das Aktualisieren von Widget-Inhalten kann rechenintensiv sein. Um den Akkuverbrauch zu senken, sollten Sie den Aktualisierungstyp, die Häufigkeit und den Zeitpunkt optimieren.

Arten von Widget-Aktualisierungen

Es gibt drei Möglichkeiten, ein Widget zu aktualisieren: eine vollständige Aktualisierung, eine Teilaktualisierung und, im Fall eines Sammlungs-Widgets, eine Datenaktualisierung. Jede hat unterschiedliche Rechenkosten und Auswirkungen.

Im Folgenden werden die einzelnen Aktualisierungstypen beschrieben und Code-Snippets für jeden Typ bereitgestellt.

  • Vollständige Aktualisierung:Rufen Sie AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) auf, um das Widget vollständig zu aktualisieren. Dadurch werden die zuvor bereitgestellten RemoteViews durch neue RemoteViews ersetzt. 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);
  • Teilaktualisierung: rufen Sie AppWidgetManager.partiallyUpdateAppWidget auf, um Teile des Widgets zu aktualisieren. Dadurch werden die neuen RemoteViews mit den zuvor bereitgestellten RemoteViews zusammengeführt. Diese Methode wird ignoriert, wenn ein Widget nicht mindestens eine vollständige Aktualisierung über updateAppWidget(int[], RemoteViews) erhält.

    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);
  • Aktualisierung der Sammlungsdaten: rufen Sie AppWidgetManager.notifyAppWidgetViewDataChanged auf, um die Daten einer Sammlungsansicht in Ihrem Widget zu ungültig zu machen. Dadurch wird RemoteViewsFactory.onDataSetChanged ausgelöst. In der Zwischenzeit werden die alten Daten im Widget angezeigt. Sie können rechenintensive Aufgaben mit dieser Methode sicher synchron ausführen.

    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, sofern die App dieselbe UID wie die entsprechende AppWidgetProvider Klasse hat.

Häufigkeit der Aktualisierung eines Widgets festlegen

Widgets werden regelmäßig aktualisiert, je nach dem Wert, der für das updatePeriodMillis Attribut angegeben wurde. Das Widget kann als Reaktion auf Nutzerinteraktionen, Broadcast-Aktualisierungen oder beides aktualisiert werden.

Regelmäßig aktualisieren

Sie können die Häufigkeit der regelmäßigen Aktualisierung steuern, indem Sie im XML-Code appwidget-provider einen Wert für AppWidgetProviderInfo.updatePeriodMillis angeben. Jede Aktualisierung löst die Methode AppWidgetProvider.onUpdate() aus, in der Sie den Code zum Aktualisieren des Widgets platzieren können. Wenn Ihr Widget jedoch Daten asynchron laden muss oder die Aktualisierung länger als 10 Sekunden dauert, sollten Sie die Alternativen für Broadcast-Receiver-Aktualisierungen in einem der folgenden Abschnitte in Betracht ziehen. Nach 10 Sekunden betrachtet das System einen BroadcastReceiver als nicht reaktionsfähig.

updatePeriodMillis unterstützt keine Werte unter 30 Minuten. Wenn Sie regelmäßige Aktualisierungen deaktivieren möchten, können Sie jedoch 0 angeben.

Sie können Nutzern erlauben, die Häufigkeit von Aktualisierungen in einer Konfiguration anzupassen. Beispielsweise möchten sie möglicherweise, dass ein Aktien-Ticker alle 15 Minuten oder nur viermal täglich aktualisiert wird. In diesem Fall legen Sie updatePeriodMillis auf 0 fest und verwenden WorkManager stattdessen.

Als Reaktion auf eine Nutzerinteraktion aktualisieren

Hier sind einige empfohlene Möglichkeiten, das Widget basierend auf Nutzerinteraktionen zu aktualisieren:

  • Über eine Aktivität der App:Rufen Sie AppWidgetManager.updateAppWidget direkt als Reaktion auf eine Nutzerinteraktion auf, z. B. wenn ein Nutzer tippt.

  • Über Remote-Interaktionen wie eine Benachrichtigung oder ein App-Widget:Erstellen Sie ein PendingIntent und aktualisieren Sie dann das Widget über die aufgerufene Activity, Broadcast oder Service. Sie können Ihre eigene Priorität auswählen. Wenn Sie beispielsweise eine Broadcast für das PendingIntent auswählen, können Sie eine Vordergrund-Broadcast auswählen, um dem BroadcastReceiver Priorität zu geben.

Als Reaktion auf ein Broadcast-Ereignis aktualisieren

Ein Beispiel für ein Broadcast-Ereignis, das eine Aktualisierung des Widgets erfordert, ist das Aufnehmen eines Fotos durch den Nutzer. In diesem Fall möchten Sie das Widget aktualisieren, wenn ein neues Foto erkannt wird.

Sie können mit JobScheduler einen Job planen und mit der JobInfo.Builder.addTriggerContentUri Methode einen Broadcast als Trigger angeben.

Sie können auch einen BroadcastReceiver für den Broadcast registrieren, z. B. um auf ACTION_LOCALE_CHANGED zu warten. Da dies jedoch Geräteressourcen verbraucht, sollten Sie diese Funktion mit Bedacht einsetzen und nur auf den jeweiligen Broadcast warten. Mit der Einführung von Broadcast Einschränkungen in Android 7.0 (API-Level 24) und Android 8.0 (API-Level 26) können Apps mit bestimmten Ausnahmen keine impliziten Broadcasts in ihren Manifesten registrieren.

Überlegungen beim Aktualisieren eines Widgets über einen BroadcastReceiver

Wenn das Widget über einen BroadcastReceiver aktualisiert wird, einschließlich AppWidgetProvider, sollten Sie die folgenden Überlegungen zur Dauer und Priorität einer Widget-Aktualisierung beachten.

Dauer der Aktualisierung

In der Regel lässt das System Broadcast-Receiver, die normalerweise im Hauptthread der App ausgeführt werden, bis zu 10 Sekunden lang laufen, bevor sie als nicht reaktionsfähig betrachtet werden und ein ANR-Fehler (Application Not Responding) ausgelöst wird. Verwenden Sie die goAsync Methode, um zu verhindern, dass der Hauptthread bei der Verarbeitung des Broadcast blockiert wird. Wenn die Aktualisierung des Widgets länger dauert, sollten Sie eine Aufgabe mit WorkManager planen.

Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.

Weitere Informationen finden Sie unter Sicherheitsüberlegungen und Best Practices.

Priorität der Aktualisierung

Standardmäßig werden Broadcasts, einschließlich der mit AppWidgetProvider.onUpdate erstellten, als Hintergrundprozesse ausgeführt. Das bedeutet, dass überlastete Systemressourcen zu einer Verzögerung beim Aufruf des Broadcast-Receivers führen können. Wenn Sie dem Broadcast Priorität einräumen möchten, machen Sie ihn zu einem Vordergrundprozess.

Fügen Sie beispielsweise das Intent.FLAG_RECEIVER_FOREGROUND Flag dem Intent hinzu, das an PendingIntent.getBroadcast übergeben wird, wenn der Nutzer auf einen bestimmten Teil des Widgets tippt.