このページでは、ユーザー エクスペリエンスを向上させるために、より高度なウィジェットを作成する際におすすめの方法について説明します。
ウィジェット コンテンツの更新の最適化
ウィジェットのコンテンツを更新すると、計算コストが高くなることがあります。バッテリー消費を抑えるには、更新タイプ、頻度、タイミングを最適化します。
ウィジェットの更新の種類
ウィジェットを更新するには、完全な更新、部分的な更新、コレクション ウィジェットの場合はデータ更新の 3 つの方法があります。それぞれ計算コストと影響が異なります。
以下に、各更新タイプについて説明し、それぞれのコード スニペットを示します。
完全更新:
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)
を介して少なくとも 1 回の完全な更新を受信していない場合、このメソッドは無視されます。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 分おきに更新する、1 日 4 回のみ更新する、といった設定ができます。この場合は、updatePeriodMillis
を 0 に設定し、代わりに WorkManager
を使用します。
ユーザーの操作に応じて更新する
ユーザー操作に基づいてウィジェットを更新するおすすめの方法をいくつかご紹介します。
アプリのアクティビティから: ユーザーのタップなどのユーザー操作に応じて、
AppWidgetManager.updateAppWidget
を直接呼び出します。通知やアプリ ウィジェットなどのリモート インタラクションから:
PendingIntent
を構築し、呼び出されたActivity
、Broadcast
、またはService
からウィジェットを更新します。優先度はご自身で選択できます。たとえば、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 秒間実行されるまで待機し、その後、応答なしと判断して Application Not Responding(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
を使用して作成されたブロードキャストを含め、ブロードキャストはバックグラウンド プロセスとして実行されます。つまり、システム リソースが過負荷になると、ブロードキャスト レシーバの呼び出しが遅延する可能性があります。ブロードキャストの優先度を上げるには、フォアグラウンド プロセスにします。
たとえば、ユーザーがウィジェットの特定の部分をタップしたときに、PendingIntent.getBroadcast
に渡される Intent
に Intent.FLAG_RECEIVER_FOREGROUND
フラグを追加します。