高度なウィジェットを作成する

このページでは、より高度なウィジェットを作成するためのおすすめの方法について説明します。 ユーザーエクスペリエンスが向上します

ウィジェット コンテンツの更新の最適化

ウィジェットのコンテンツを更新すると、計算コストが高くなる可能性があります。バッテリーを節約するため 更新の種類、頻度、タイミングを最適化します。

ウィジェットの更新の種類

ウィジェットを更新する方法には、完全な更新、部分更新、 データを更新しますそれぞれに異なる 影響を及ぼします

以下では、各更新タイプについて説明し、それぞれのコード スニペットを示します。

  • フル アップデート: 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);
    

これらのメソッドは、 同じ UID を AppWidgetProvider クラス。

ウィジェットを更新する頻度を決定する

ウィジェットは、 updatePeriodMillis 属性です。ウィジェットは、ユーザーの操作、ブロードキャスト、 実行できます。

定期的に更新する

定期的な更新の頻度を制御するには、 appwidget-provider XML 内の AppWidgetProviderInfo.updatePeriodMillis。各 update は AppWidgetProvider.onUpdate() メソッドをトリガーします。 ウィジェットを更新するコードを配置できますただし、別の仮想マシン(VM)に ブロードキャスト レシーバの更新が記述され、 ウィジェットでデータを非同期で読み込む必要がある場合や、 更新に 10 秒はかかります。10 秒が経過すると、システムは更新に BroadcastReceiver は、応答しなくなります。

updatePeriodMillis は 30 分未満の値に対応していません。ただし、 定期的な更新を無効にする場合は、0 を指定します。

管理者は、ユーザーが構成の更新頻度を調整できるようにすることができます。対象 たとえば、株式相場を 15 分ごとや 4 分の 1 ごとに です。この場合、updatePeriodMillis を 0 に設定して、 WorkManager をご利用ください。

ユーザーの操作に応じて更新する

ユーザーの操作に応じてウィジェットを更新するためのおすすめの方法を以下に示します。

  • アプリのアクティビティから: 直接呼び出します。 AppWidgetManager.updateAppWidget のようなユーザー インタラクション( 認識できます。

  • 通知やアプリ ウィジェットなどのリモート操作から: PendingIntent を作成してから、呼び出された場所からウィジェットを ActivityBroadcastService。優先度はご自身で選択できます。対象 たとえば、PendingIntentBroadcast を選択した場合、 フォアグラウンド ブロードキャストを使用して、 優先度 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 応答中(ANR)エラー。テストの実施に 次の方法を検討してください。

  • WorkManager を使用してタスクのスケジュールを設定します。

  • メッセージで応答時間を長くする goAsync メソッドを使用します。 これにより、レシーバーは 30 秒間実行できます。

セキュリティに関する考慮事項とベスト プラクティスを プラクティスをご覧ください。 情報です。

アップデートの優先度

デフォルトでは、ブロードキャスト( AppWidgetProvider.onUpdate - バックグラウンド プロセスとして実行します。つまり システム リソースが過負荷状態になると、ブロードキャストの呼び出しが遅延する可能性がある 受信します。ブロードキャストを優先するには、フォアグラウンド プロセスにします。

たとえば、 Intent.FLAG_RECEIVER_FOREGROUND PendingIntent.getBroadcast に渡される Intent にフラグを ウィジェットの特定の部分をタップしたときに 通知を受け取ることができます

動的アイテムを含む正確なプレビューを作成する

<ph type="x-smartling-placeholder">
</ph>
図 1: リストアイテムが表示されていないウィジェットのプレビュー

このセクションでは、 コレクションを含むウィジェットのウィジェット プレビュー ビューがあります。つまり、 ListViewGridView、または StackView

ウィジェットでこれらのビューのいずれかを使用している場合、直接 実際のウィジェットを レイアウトによって ウィジェットのプレビューにアイテムが表示されない場合があります。これは次の理由で発生します。 コレクション ビューのデータは実行時に動的に設定され、 図 1 に示します。

コレクション ビューを含むウィジェットのプレビューがウィジェット内で正しく表示されるようにする 専用のレイアウト ファイルを プレビューします。この個別のレイアウト ファイルには、実際のウィジェット レイアウトと、 架空のアイテムを含むプレースホルダ コレクション ビュー。たとえば、Python や Curl など、 ListView(プレースホルダ LinearLayout といくつかの架空のリストを指定) あります。

ListView の例を示すために、別のレイアウト ファイルから始めます。

// 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>

次の previewLayout 属性を指定する場合は、プレビュー レイアウト ファイルを指定します。 AppWidgetProviderInfo メタデータ。実際のウィジェット レイアウトは、引き続き指定します。 initialLayout 属性用とし、場合は実際のウィジェット レイアウトを使用します。 実行時に RemoteViews を作成します。

<appwidget-provider
    previewLayout="@layout/widget_previe"
    initialLayout="@layout/widget_view" />

複雑なリストアイテム

前のセクションの例では、架空のリストアイテムを使用しています。 アイテムは TextView オブジェクトです。かもしれない アイテムが複雑なレイアウトの場合、架空のアイテムを提供するのはより複雑になります。

widget_list_item.xml で定義され、次の要素で構成されるリストアイテムについて考えてみましょう。 2 つの 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>

架空のリストアイテムを提供するには、レイアウトを複数回インクルードできますが、 各リスト項目が同一になります。固有のリストアイテムを指定するには、 手順は次のとおりです。

  1. テキスト値の属性セットを作成します。

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. 次の属性を使用してテキストを設定します。

    <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. プレビューに必要な数のスタイルを作成します。Deployment の 各スタイル:

    <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. プレビュー レイアウトの架空のアイテムにスタイルを適用します。

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