建立進階小工具

試試 Compose 方式
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何使用 Compose 樣式的 API 建構小工具。

本頁面說明如何建立更進階的小工具,提供更優質的使用者體驗。

更新小工具內容的最佳化做法

更新小工具內容的運算成本可能很高。如要節省電池用量,請最佳化更新類型、頻率和時間。

小工具更新類型

更新小工具的方式有三種:完整更新、部分更新,以及 (如果是集合小工具) 重新整理資料。每種方法都有不同的運算成本和影響。

以下說明各更新類型,並提供每種更新類型的程式碼片段。

  • 完整更新:呼叫 AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) 完整更新小工具。這會將先前提供的 RemoteViews 替換為新的 RemoteViews。這是運算成本最高的更新。

    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);
  • 部分更新:呼叫 AppWidgetManager.partiallyUpdateAppWidget 更新小工具的部分內容。這會將新的 RemoteViews 與先前提供的 RemoteViews 合併。如果小工具未透過 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);
  • 集合資料重新整理:呼叫 AppWidgetManager.notifyAppWidgetViewDataChanged ,使小工具中的集合檢視區塊資料失效。這會觸發 RemoteViewsFactory.onDataSetChanged。在此期間,小工具會顯示舊資料。您可以使用這個方法,安全地同步執行耗費資源的工作。

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

只要應用程式與對應的 AppWidgetProvider 類別具有相同的 UID,您就可以從應用程式中的任何位置呼叫這些方法。

決定小工具的更新頻率

小工具會定期更新,實際更新情形取決於 updatePeriodMillis 屬性提供的值。小工具可以回應使用者互動、播送更新,或同時執行這兩項操作。

定期更新

如要控制定期更新的頻率,請在 appwidget-provider XML 中指定 AppWidgetProviderInfo.updatePeriodMillis 的值。每次更新都會觸發 AppWidgetProvider.onUpdate() 方法,您可以在其中放置程式碼來更新小工具。不過,如果小工具需要非同步載入資料或更新時間超過 10 秒,請考慮使用廣播接收器更新的替代方案,詳情請參閱下一個章節。這是因為系統會在 10 秒後將 BroadcastReceiver 視為沒有回應。

updatePeriodMillis 不支援小於 30 分鐘的值。不過,如要停用定期更新,可以指定 0。

您可以在設定中讓使用者調整更新頻率。舉例來說,他們可能希望股票代號每 15 分鐘更新一次,或每天只更新四次。在這種情況下,請將 updatePeriodMillis 設為 0,並改用 WorkManager

根據使用者互動更新

以下是根據使用者互動更新小工具的建議方式:

  • 從應用程式的活動:直接呼叫 AppWidgetManager.updateAppWidget,以回應使用者互動,例如使用者輕觸。

  • 透過遠端互動 (例如通知或應用程式小工具): 建構 PendingIntent,然後從叫用的 ActivityBroadcastService 更新小工具。您可以自行選擇優先順序。舉例來說,如果您為 PendingIntent 選取 Broadcast,可以選擇前景廣播,將優先順序設為 BroadcastReceiver

根據廣播事件更新

舉例來說,使用者拍照時,就需要廣播事件來更新小工具。在這種情況下,您希望系統在偵測到新相片時更新小工具。

您可以使用 JobScheduler 安排工作,並使用 JobInfo.Builder.addTriggerContentUri 方法指定廣播做為觸發條件。

您也可以為廣播註冊 BroadcastReceiver,例如監聽 ACTION_LOCALE_CHANGED。不過,這會耗用裝置資源,因此請謹慎使用,並只收聽特定廣播。Android 7.0 (API 級別 24) 和 Android 8.0 (API 級別 26) 推出廣播限制後,應用程式無法在資訊清單中註冊隱含廣播,但有某些例外狀況

從 BroadcastReceiver 更新小工具時的注意事項

如果小工具是從 BroadcastReceiver (包括 AppWidgetProvider) 更新,請注意下列有關小工具更新時間和優先順序的考量事項。

更新時間長度

一般來說,系統會允許廣播接收器 (通常在應用程式的主執行緒中執行) 執行最多 10 秒,之後就會將其視為無回應,並觸發「應用程式無回應」(ANR) 錯誤。為避免在處理廣播時封鎖主執行緒,請使用 goAsync 方法。如果更新小工具的時間較長,建議使用 WorkManager 排定工作。

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

詳情請參閱安全性考量事項和最佳做法

更新優先順序

根據預設,廣播 (包括使用 AppWidgetProvider.onUpdate 建立的廣播) 會以背景程序的形式執行。這表示系統資源過載可能會導致廣播接收器延遲叫用。如要優先處理廣播,請將其設為前景程序。

舉例來說,當使用者輕觸小工具的特定部分時,請將 Intent.FLAG_RECEIVER_FOREGROUND 標記新增至傳遞至 PendingIntent.getBroadcastIntent