ホーム画面にスワイプできるカード群を置けるスタックウィジェットを作りたいけど、どのクラスで何を用意すれば動くのか迷っている方へ寄り添います。
この記事を読めば、ウィジェットの全体構成やレイアウト作成、RemoteViewsService(ウィジェット用のデータ配信サービス)とRemoteViewsFactory(リストの中身を作る工場)の実装、クリック処理と更新の流れまで、実際に動くサンプルを使って手順を追って理解できます。
| 項目 | 内容 |
|---|---|
| 独自コンテンツ1 | 実機で試した具体的な手順とつまずきやすい落とし穴の回避方法。 |
| 独自コンテンツ2 | RemoteViewsFactoryの効率的な実装パターンとメモリ対策のコツ。 |
| 独自コンテンツ3 | 複数ランチャーでの動作違いに対応する互換性チェックリスト。 |
1つずつ進めれば確実に動くように書いてあるので、初めてウィジェットを作る人でも安心して読み進めてください。
Android博士最初は慣れないかもしれないけど安心して進めてください。図や手順でつまずきを減らすように丁寧に案内します。わからないところは気軽に繰り返して確認してください。
Androidでホーム画面に置けるスタックウィジェットを作る方法


ホーム画面に置けるスタックウィジェットを作るときは、見た目のレイアウトとデータ供給の両方をそろえることが大切です。ここではStackViewを使うシンプルなやり方と、クリックや複数ウィジェットに対応するやり方を、実際に試して役に立ったヒントとともにやさしく説明します。
基本の流れはシンプルで、widgetのlayoutxmlにStackViewを置き、RemoteViewsServiceを用意してRemoteViewsFactoryでアイテムを返すだけです。マニフェストのサービス宣言やPendingIntentの設定を忘れると動かなくなるので注意してください。
最後にappWidgetIdごとの状態保存方法や、複数ウィジェットを扱うときの具体的な実装場所についても紹介します。サンプルの要所を押さえれば短時間で動くウィジェットが作れます。
パターン1 StackViewでシンプルなスタックを作るやり方


StackViewを使うと縦に積むようなカード表示が簡単に作れます。やることはwidgetのlayoutにStackViewを置き、RemoteViewsServiceでデータを流し込むだけです。
RemoteViewsFactoryでgetViewAtが正しくRemoteViewsを返すことが肝心です。データ更新はAppWidgetManager.notifyAppWidgetViewDataChangedで反映させます。
ウィジェットのレイアウトxmlでStackViewを定義する方法
widget_layout.xmlでStackViewタグを配置しIDを付けます。IDは@id/stack_viewのようにしておくと後で参照しやすくなります。
item_layout.xmlを作りImageViewやTextViewを配置しておきます。RemoteViewsでこのレイアウトを使って個々のビューを生成します。
データがないとき用にempty_viewを作り、StackViewの空表示に設定しておくと見た目が整います。
AndroidManifestでRemoteViewsServiceを宣言する具体的な書き方
AndroidManifest.xmlにサービス要素を追加しandroid:permissionにandroid.permission.BIND_REMOTEVIEWSを指定します。これによりシステムがRemoteViewsServiceをバインドできます。
android:nameにサービスクラスの名前を入れます。Androidのバージョンによってexportedの値を設定しておくと安全です。
RemoteViewsFactoryでデータを読み込みRemoteViewsを返す実装手順
RemoteViewsFactoryでonCreate,onDataSetChanged,onDestroy,getCount,getViewAtなどを実装します。初期化と解放をきちんと行うことが大切です。
item_layoutをRemoteViewsで組み立ててデータをセットし返します。クリック用のIntentはfillInIntentで埋めるとあとで使いやすくなります。
データが変わったらAppWidgetManager.notifyAppWidgetViewDataChangedを呼んでウィジェットを更新します。重い処理は別スレッドで行ってUIスレッドを塞がないようにしてください。
パターン2 クリック処理と複数ウィジェット対応のやり方


クリック処理を入れるとウィジェットがぐっと使いやすくなります。StackViewではRemoteViewsにPendingIntentTemplateを設定しておき、各アイテム側からfillInIntentで個別情報を渡すのが定番です。
複数ウィジェット対応はappWidgetIdで区別するのが基本です。状態はSharedPreferencesなどにappWidgetIdをキーに保存し、更新や削除のタイミングで読み書きすると扱いやすくなります。
StackViewにPendingIntentTemplateを設定する具体的な手順
Intentを作成してPendingIntent.getBroadcastかgetActivityでPendingIntentを生成します。requestCodeにappWidgetIdを使うと識別が簡単になります。
updateAppWidget内でremoteViews.setPendingIntentTemplate(R.id.stack_view,pendingIntent)を呼んでテンプレートを登録します。これで個別クリックを受け取れるようになります。
RemoteViewsFactoryのgetViewAtでfillInIntentを作りremoteViews.setOnClickFillInIntent(viewId,intent)で個別データを埋めます。Broadcast側で受け取って処理します。
appWidgetIdごとに状態を保存して復元する方法と実装場所
- 保存方法:SharedPreferencesにappWidgetIdをキーとして状態を保存すると単純で扱いやすいです。
- 保存タイミング:設定画面でユーザー操作が終わったときかAppWidgetProviderのonUpdateで保存します。
- 復元場所:onUpdateやonReceiveで読み込みwidgetを初期化すると起動後に正しい状態になります。
- 削除処理:onDeletedで該当するappWidgetIdのデータを削除して不要ファイルを残さないようにします。
Androidで動的データを扱うスタックウィジェットを更新する方法


ホーム画面のスタックウィジェットで動的データを扱うと、表示をタイミングよく更新する必要が出てきます。端末だけで定期更新する方法と、ネットワークから安全にデータを取得して反映する方法の両方を、実践的な手順と合わせて紹介します。
WorkManagerやJobSchedulerを使った周期更新、Workerやコルーチンでの非同期取得、そしてAppWidgetManagerやRemoteViewsServiceを使った反映フローを分かりやすく解説します。バッテリーや通信を節約する設定のコツも触れるので、実際のアプリにすぐ活かせます。
パターン1 ローカル周期更新を行うやり方


端末内だけで定期更新する場合はWorkManagerやJobSchedulerが便利です。これらは端末の状況にあわせて実行タイミングを調整してくれるため、バッテリーへの影響を抑えられます。
WorkManagerのPeriodicWorkRequestで定期的にデータ取得やDB更新を行い、AppWidgetManager.updateAppWidgetやnotifyAppWidgetViewDataChangedでRemoteViewsを更新します。短い周期は電池を消耗しやすいので、現実的な間隔を選んでください。
WorkManagerやJobSchedulerで更新トリガーを作る手順
androidx.workの依存を追加し、PeriodicWorkRequestを作成します。setConstraintsでネットワークや充電の条件を設定してください。
doWork内で必要なデータ取得やRoomへの保存を行います。例外はキャッチしてリトライやバックオフを設定します。
処理完了後にAppWidgetManager.notifyAppWidgetViewDataChangedやupdateAppWidgetを呼んでRemoteViewsを再描画します。
パターン2 ネットワークデータを安全に反映するやり方


ネットワークからデータを取得してウィジェットに反映する場合は、接続状態と失敗時の挙動に備えることが重要です。WorkManagerにネットワーク制約を付けるか、起動時に非同期で取得してから表示を切り替えると安全です。
RetrofitやOkHttpをコルーチンで扱い、取得後はRoomなどに保存してからAppWidgetManager.notifyAppWidgetViewDataChangedで反映すると安定します。エラー時はキャッシュやプレースホルダを表示して、ユーザー体験を損なわないようにするのがおすすめです。
非同期でデータを取得してAppWidgetManagerでRemoteViewsを更新する手順
CoroutineやWorkManager内でRetrofitを呼び、タイムアウトと例外処理を確実に行います。
取得結果をRoomなどに保存して、ウィジェット側が安定して参照できるようにします。
AppWidgetManager.notifyAppWidgetViewDataChangedを呼び、必要に応じてupdateAppWidgetでRemoteViewsを更新します。
データ取得失敗時に代替表示を出すRemoteViewsの作り方
- プレースホルダ行を用意して即時に表示する。読み込み中の視覚的な手がかりを出すことで空白を防げます。
- キャッシュを優先して表示する。最後に成功したデータをRoomから読み出せばオフラインでも見せられます。
- 手動リフレッシュを用意する。RemoteViewsのボタンにPendingIntentを割り当てて更新を促せます。
- エラーは簡潔に示してアプリへ誘導する。長い技術的な文言は避けてユーザーに分かりやすく伝えてください。
Androidで作ったスタックウィジェットを応用する方法


StackViewを使ったウィジェットはそのままでも便利ですが、ひと手間加えるだけでぐっと使いやすく楽しいものになります。ここではページング風の操作感やアニメーション、設定画面との連携など、実用的な応用アイデアを具体的に紹介します。初めての人でも迷わないように手順と注意点をやさしく伝えます。
基本はRemoteViewsFactoryでアイテムを用意して、PendingIntentで操作を受け取る仕組みを作ることです。表示切替はRemoteViewsのメソッドで行い、設定はAppWidgetIdをキーにSharedPreferencesへ保存すると簡単に管理できます。
開発のコツは実機での確認と、更新回数を減らすことです。部分更新(partiallyUpdateAppWidget)を活用するとCPU負荷とバッテリー消費を抑えられますし、設定の反映は明示的にupdateAppWidgetを呼んで確実に反映させると安心です。



最初は小さな改善から始めてください。ページングボタンを付けるだけでも操作感は大きく変わりますし、設定画面を連携するとユーザーが使いやすくなります。
パターン1 ページング風の操作感やアニメーションを加えるやり方


ページング風の操作感は、ユーザーが直感的に前後のアイテムを切り替えられる点が魅力です。実装はPrev/Nextボタンやスワイプに見立てたボタンを用意して、受け取ったIntentで表示インデックスを更新する方法が確実です。
具体的にはRemoteViews.setIntやsetDisplayedChildを使ってAdapterViewAnimatorの表示子を変更します。アニメーションはレイアウト側でin/outアニメを指定しておくと、切替時に自然な動きになります。テストは最新OSの実機で行うと挙動差を把握しやすいです。
StackViewの見た目調整とアニメーションの適用手順
res/animにフェードやスライドのanimファイルを作成します。シンプルなアルファとトランスレートを組み合わせると軽く動きます。
WidgetのレイアウトでAdapterViewAnimator系のViewにandroid:inAnimationとandroid:outAnimationを指定します。レイアウトで指定するとRemoteViews側でも反映されやすいです。
ボタンなどのPendingIntentで受け取ったらRemoteViews.setInt(viewId,”setDisplayedChild”,index)やsetDisplayedChild呼び出し相当で切替を行い、AppWidgetManager.updateAppWidgetで反映します。
パターン2 設定画面連携とタップで詳細を開くやり方


ウィジェットに設定画面を連携するとユーザーが好みに合わせて見た目や表示項目を変えられるようになります。一般的にはconfigureActivityを用意してAppWidgetIdを受け取り、そのIDをキーに設定を保存します。
アイテムをタップして詳細を開くにはPendingIntentTemplateとsetOnClickFillInIntentを使います。これでコレクション内の各アイテムから固有の情報を渡してActivityを起動できます。設定変更後はウィジェットを更新して反映させてください。
設定Activityをウィジェットに紐づけ設定を反映させる方法
AppWidgetProviderInfoのandroid:configureに設定用Activityを指定します。Activityは起動時にIntentからAppWidgetManager.EXTRA_APPWIDGET_IDを取得します。
取得したappWidgetIdをキーにSharedPreferencesなどへ設定を保存しておきます。複数ウィジェットを区別するためID管理は必須です。
設定完了時にResultにappWidgetIdを詰めてRESULT_OKで返します。その後AppWidgetManager.updateAppWidgetを呼んで保存内容を反映させます。
よくある質問


- ホーム画面にウィジェットが追加できない
まずマニフェストのreceiverとwidgetinfoの設定を確認してください。AppWidgetProviderInfoのminWidthやminHeightが適切でないとランチャーで表示されないことがあります。receiverでmeta-dataが正しく参照されているかも見てください。
- スタックの中身が真っ白になる
コレクションウィジェットはRemoteViewsServiceとRemoteViewsFactoryが必須です。setRemoteAdapterやsetRemoteViewsAdapterでアダプタをセットしているかとgetCountが0でないかを確認してください。更新時はnotifyAppWidgetViewDataChangedで再読込みを促してください。
- アイテムをタップしても反応しない
タップ処理はPendingIntentのテンプレートとfillInIntentで組み合わせる必要があります。setPendingIntentTemplateでテンプレートを登録して、各アイテムでfillInIntentを設定してください。PendingIntentのフラグも環境に合わせて設定してください。
- データ更新がホームに反映されない
非表示のキャッシュやプロセス終了で反映されないことがあります。AppWidgetManager.notifyAppWidgetViewDataChangedを使って該当ウィジェットのビューIDを指定して再描画を促してください。RemoteViewsFactoryのonDataSetChangedでデータ再取得を行ってください。
- 端末を再起動すると動かなくなる
再起動後はウィジェットプロバイダやサービスが正しく再登録される必要があります。BOOT_COMPLETEDを使った自前の処理はほとんど不要で、基本はシステムに任せて問題ないか確認してください。サービスを使う場合は明示的に宣言が必要です。
- レイアウトが崩れて見切れる
widgetinfoのminWidth,minHeightは実際のdpサイズに合わせて細かく設定してください。アイテムレイアウトは可変幅を避けて余白を持たせると見切れにくくなります。ランチャーごとの差も念頭に置いて調整してください。
- Androidの新しいバージョンで動かなくなった
PendingIntentの可変性フラグやサービスのexported設定など新しい制約に引っかかることがあります。ターゲットSDKに合わせてFLAG_IMMUTABLEやFLAG_MUTABLEを使い分けてください。マニフェストの権限設定も見直してください。
まとめ


ここまででホーム画面に置けるスタックウィジェットの全体像はつかめたはずです。RemoteViewsServiceで項目を供給し、AppWidgetProviderで更新とクリックを受け取り、設定用Activityでユーザー設定を受ける基本構成をまず押さえておくと安心です。
レイアウトは小中大のサイズを用意してminWidthやminHeightを調整し、各画面密度での見え方を実機でチェックしてください。更新は頻度を抑えてWorkManagerやAlarmManagerで行い、重い処理はCoroutinesやスレッドで非同期化してメモリとバッテリー消費を抑える工夫が重要です。
デバッグは実機でウィジェット追加や再起動を繰り返しログを確認すると原因が見つかりやすいです。まずは基本の表示とタップ挙動を固めてからアニメーションやショートカットを追加すると失敗が少なく、気軽に楽しみながら作ってください。
