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

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

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

ウィジェットのコンテンツを更新すると、計算コストが高くなる可能性があります。バッテリー消費を抑えるには、更新タイプ、頻度、タイミングを最適化します。

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

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

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

  • 完全な更新: 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 分おきに更新する、1 日 4 回のみ更新する、といった設定ができます。この場合、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 からウィジェットを更新する際の考慮事項

ウィジェットが BroadcastReceiverAppWidgetProvider を含む)から更新される場合は、ウィジェットの更新時間と優先度に関する次の考慮事項に注意してください。

更新の所要時間

原則として、ブロードキャスト レシーバは、通常はアプリの 最大 10 秒間実行した後で、そのスレッドは応答しないと見なされ、 Application Not 応答中(ANR)エラー。ウィジェットの更新に時間がかかる場合は、次の代替手段を検討してください。

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

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

詳細については、セキュリティに関する考慮事項とベスト プラクティスをご覧ください。

アップデートの優先度

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

たとえば、ユーザーがウィジェットの特定の部分をタップしたときに PendingIntent.getBroadcast に渡される IntentIntent.FLAG_RECEIVER_FOREGROUND フラグを追加します。

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

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