Androidウィジェットを作ってみたいけれど公式の説明が難しくて途中でつまずいていませんか。
この記事を読めば最短で動くウィジェットが作れるようになりホーム画面に自分だけの情報を表示できるようになります。実際の開発で役立つ具体的な手順とつまずきやすいポイントを優しく丁寧に解説します。
| 項目 | 内容 |
|---|---|
| 動く最小限サンプル | そのまま動かせるサンプルコードと動作の仕組みがわかる解説。 |
| レイアウトとRemoteViewsのコツ | 見た目を崩さず効率よく更新するための実用テクニック。 |
| 実機でのテストと省電力運用 | 更新頻度の決め方やバッテリーに優しい処理方法を具体例で紹介。 |
まずは小さなウィジェットを作って動かしてみましょう。動いたときの楽しさが次の学びを自然に引き出します。
Android博士最初は戸惑うのが当たり前ですから慌てず一歩ずつ進めてください。困ったときは落ち着いてログを見れば答えが見つかります。
Androidでホームウィジェットを作る実践手順


ホームウィジェットは画面上で情報をさっと見せて、タップで操作を受け取れる小さなアプリのような存在です。ここではレイアウト作成からAppWidgetProvider設定、onUpdateでのRemoteViewsとPendingIntentの紐付けまで、実際に手を動かして学べる流れで説明します。
最新のAndroidではupdatePeriodMillisが制限されるため、ボタン操作やWorkManagerを組み合わせて更新設計を考えると安心です。端末でウィジェットを追加してこまめに動作確認すると問題解決が早くなります。
- app→res→layoutにwidget_layout.xmlを作る
- AppWidgetProviderクラスとres→xmlのappwidget_provider.xmlを用意する
- onUpdateでRemoteViewsを作りボタンにPendingIntentをセットする
- AndroidManifestのreceiverにmeta-dataでウィジェットを登録する
- 端末で追加して動作確認しログで問題を追う



まずは小さなウィジェットを一つ作って、表示とクリックが両方動く喜びを味わってください。エラーが出ても慌てずログを追えば解決の糸口が見つかります。
情報表示とクリック操作を組み合わせる実践パターン


情報表示とクリック操作を組み合わせるときは、表示更新とユーザー操作の受け取りを分けて考えると楽になります。RemoteViewsでTextViewやImageViewを更新しつつ、setOnClickPendingIntentでタップを受け取るのが基本です。
タップ処理はBroadcastで受け取るかActivityを起動するか選べますが、ウィジェット内で完結する処理はgetBroadcastが扱いやすいです。Android12以降はPendingIntentのFLAG_IMMUTABLEやFLAG_MUTABLEに注意して作成してください。
AndroidStudioのProjectでapp→res→layoutにwidget_layout.xmlを作る
app→res→layoutにwidget_layout.xmlを作りルートにConstraintLayoutやLinearLayoutを置きます。
TextViewやButtonにidを付けておき幅高さはwrap_contentやdpで指定しプレビューで確認します。
RemoteViewsではカスタムViewや一部プロパティが使えないため標準ビュー中心で設計します。
appのパッケージにAppWidgetProviderクラスを作りres→xmlにappwidget_provider.xmlを追加する
appのパッケージにクラスを作りAppWidgetProviderを継承してonUpdateを実装します。
res→xmlにappwidget_provider.xmlを作りminWidthやminHeight、initialLayoutなどを設定します。
AndroidManifestのreceiverにandroid.appwidget.providerのmeta-dataで@xml/appwidget_providerを参照させて登録します。
AppWidgetProviderのonUpdateでRemoteViewsを作りボタンにPendingIntentをセットする
onUpdateでRemoteViewsをnew RemoteViews(context.getPackageName(),R.layout.widget_layout)で作成します。
Intentを用意しPendingIntent.getBroadcastやgetActivityでPendingIntentを作りAndroid12以上はFLAG_IMMUTABLEなどを忘れないようにします。
remoteViews.setOnClickPendingIntent(viewId,pendingIntent)でボタンに紐付けしappWidgetManager.updateAppWidget(appWidgetId,remoteViews)で反映します。
Androidでコレクションウィジェットを作る実践手順


ホーム画面に動くリストを置きたいときはRemoteViewsServiceを使うのが王道です。実際にはサービスでアイテムごとのRemoteViewsを返す仕組みを作り、ウィジェット側でそのサービスを参照するだけでリスト表示ができます。
作る流れはシンプルで、サービスとFactoryの実装、行レイアウトとウィジェット全体レイアウトの用意、AppWidgetProviderでsetRemoteAdapterを呼んで紐づけるだけです。更新はnotifyAppWidgetViewDataChangedで行い、クリック処理はfillInIntentを使うと扱いやすいです。



最初は細かいメソッドが多くてとまどうかもしれませんが、ひとつずつ実装して動くと達成感が大きいです。ここは落ち着いて順番に進めていきましょう。
RemoteViewsServiceでリストを表示するパターン


RemoteViewsServiceパターンではService側でRemoteViewsFactoryを返し、Factory内でデータの読み込みと各アイテムのRemoteViews構築を行います。ウィジェット側はListViewやStackViewを配置してsetRemoteAdapterでサービスを接続するだけです。
重要な点はgetViewAtで返すRemoteViewsは軽くすることと、重い処理は背景スレッドで行うことです。データ更新は適切にnotifyAppWidgetViewDataChangedを呼んで反映させ、クリックはfillInIntentで個別処理に渡すと扱いやすいです。
appのjavaパッケージにRemoteViewsServiceとRemoteViewsFactoryを実装する
android.appwidget用のServiceとしてRemoteViewsServiceを継承して実装し、onGetViewFactoryでFactoryを返すようにします。
FactoryでonCreate,onDataSetChanged,onDestroy,getCount,getViewAtなど必須メソッドを実装し、getViewAtで行ごとのRemoteViewsを組み立てます。
データ取得は可能な限り軽くし、DBやネットは背景スレッドで行って結果をonDataSetChangedで反映してください。
res→layoutに行レイアウトとウィジェット本体レイアウト(ListView)を作りServiceを紐づける
リストの各行用にRemoteViewsで使うレイアウトを作成し、テキストやアイコンに対応するViewにidを振ります。
ウィジェット全体のレイアウトにListView系のViewを配置し、空の場合のemptyViewも用意しておきます。
AppWidgetProviderのonUpdateでRemoteViews#setRemoteAdapterにRemoteViewsServiceのIntentを渡して接続し、setEmptyViewやsetPendingIntentTemplateを設定します。
Androidでウィジェットの更新とテストを行う方法


ウィジェットは単に見た目を表示するだけではなく更新タイミングや省電力対応がとても重要です。実務で役立つ手順をわかりやすく伝えます。
基本的な流れはRemoteViewsでレイアウトを組み替えAppWidgetManagerに更新を依頼することです。定期更新にはWorkManagerのPeriodicWorkRequestを使いイベント更新はBroadcastReceiverやPendingIntentで受け取ると安定します。
テストはエミュレータで素早く動作確認し実機で最終チェックするのが近道です。実機ではホームランチャーや省電力設定の影響が出ることがあるので必ず実機で確認してください。
定期更新と実機/エミュレータでの確認


PeriodicWorkRequestは繰り返し実行を安定させつつシステム負荷を抑えるのに向いています。最小間隔は15分なので短周期のテストは別手段で行うとスムーズです。
実機ではバッテリー最適化やメーカー独自の省電力機能が影響するので設定を無効化して確認すると原因追跡が楽になります。エミュレータではウィジェットの再配置やログ確認で早く動作確認できます。
MainActivityなどでPeriodicWorkRequestを作成してWorkManagerからRemoteViews更新処理を呼ぶ
build.gradleにWorkManagerの依存関係を追加して準備します。Ktx版を入れるとコードが簡潔になります。
WorkerのdoWork内でAppWidgetManagerとRemoteViewsを使ってウィジェットを更新します。ウィジェットIDを引き渡す実装か全体更新を行う実装にします。
PeriodicWorkRequestBuilderで間隔を設定しenqueueUniquePeriodicWorkで登録します。ExistingPeriodicWorkPolicy.REPLACEを使うと古いジョブが残らず安心です。
Android Studioのエミュレータまたは実機でホーム画面を長押し→ウィジェット→アプリを選んで配置して動作を確認する
エミュレータは最新のAndroidイメージを使い実機はデバッグモードを有効にします。ホームランチャーが標準的な挙動か確認しておきます。
ホーム画面を長押ししてウィジェットを選びアプリのウィジェットを見つけて配置します。ドラッグでサイズを調整して望む見た目に合わせます。
ログやToastで更新が呼ばれるか確認し反映されない場合はWorkManagerやバッテリー最適化設定をチェックします。実機ではランチャーごとの表示差も必ず確認してください。
応用編 Androidウィジェットの高度なやり方


ウィジェットをもう一歩進めると、利用者が本当に便利に感じる仕上がりになります。ここではサイズ可変や複数同時配置に対応するコツを、実務で使える手順として分かりやすく紹介します。
まずはres/xmlのappwidget_providerでresizeModeやminWidth/minHeightを正しく設定することが肝心です。次にAppWidgetProviderのonAppWidgetOptionsChangedで実際のサイズを受け取り、表示レイアウトを差し替える流れが定番です。
個別のウィジェットごとに設定を保存するにはappWidgetIdをキーにしてSharedPreferencesやDatastoreに書き込むと扱いやすいです。更新はAppWidgetManager.updateAppWidgetやWorkManagerを使い、重い処理は別スレッドで行ってください。



ちょっとした工夫でユーザーの満足度がぐっと上がるので、怖がらずに少しずつ試してみてくださいね。バグが出たらログを見て冷静に直していけば必ず前に進めます。
サイズ変更対応と複数インスタンス対応の具体手順


サイズ変更と複数インスタンス対応の基本はシンプルです。ウィジェット側で渡されるサイズ情報に応じて適切なRemoteViewsを選び、各インスタンスの設定はappWidgetId単位で保存します。
- res/xmlのappwidget_providerでresizeModeやminWidth/minHeightを設定する。
- onAppWidgetOptionsChangedでBundleからサイズ情報を取得する。
- サイズに応じてRemoteViewsのレイアウトを切り替える。
- appWidgetIdをキーにSharedPreferencesやDatastoreへ個別設定を保存する。
- AppWidgetManager.updateAppWidgetで変更を反映させる。
res→xmlのappwidget_providerでresizeModeやminWidth/minHeightを設定する
| 項目 | 内容 |
|---|---|
| resizeMode | resizeMode=”horizontal|vertical|none”と設定すると横方向や縦方向のリサイズを許可できます。 |
| minWidth/minHeight | minWidth/minHeightでdp単位の最小サイズを指定します。ホーム画面のセル幅に合わせて切り上げると見た目が整います。 |
| 実用的なヒント | 端末やランチャーでセルサイズが異なるため実機で確認してください。必要ならminResizeWidth/minResizeHeightも検討してください。 |
AppWidgetProviderのonAppWidgetOptionsChangedでサイズに応じたRemoteViewsを切り替え、appWidgetIdごとの設定を保存する
onAppWidgetOptionsChangedで渡されるoptionsBundleからOPTION_APPWIDGET_MIN_WIDTHなどを読み出します。
取得した幅や高さに応じて表示候補のRemoteViewsを選び、必要なViewの可視性や配置を切り替えます。
appWidgetIdをキーにSharedPreferencesやDatastoreへ状態を保存し、AppWidgetManager.updateAppWidgetで反映します。重い処理は別スレッドで行ってください。
よくある質問


- ウィジェットをホームに追加できません。
マニフェストのreceiverとres/xmlのAppWidgetProviderInfoが正しく設定されているかまず確認してください。minWidthやminHeightが不適切だとホームに追加できないことがあるので値を見直してください。
- ウィジェットの更新が反映されません。
updatePeriodMillisだけに頼ると端末によって動かないことがあるので、WorkManagerやAlarmManagerで確実に更新をトリガーしてください。リスト系のウィジェットはnotifyAppWidgetViewDataChangedを呼んでビューを更新してください。
- レイアウトが崩れてサイズが合いません。
RemoteViewsは使えるビューに制約があるので、複雑なカスタムビューは避けてシンプルな構成にしてください。appwidget-providerのdp計算ルールに合わせてminWidthとminHeightを調整し、実機で確認しながら直してください。
- ウィジェットのタップで動作しません。
PendingIntentの生成方法やflags、リクエストコードに問題がないか確認してください。バックグラウンド制限で動かないケースもあるので、必要ならユーザー操作で許可を促すかフォアグラウンドで処理する方法を検討してください。
まとめ


まとめとして、Androidのホームウィジェットを作る流れは思ったより単純です。ウィジェットのレイアウトをXMLで作って、AppWidgetProviderとAppWidgetProviderInfoを用意し、RemoteViewsでUI更新とPendingIntentを使ったタップ処理を実装します。
よくつまずくポイントは三つあります。updatePeriodMillisだけに頼ると制約で動かないことがあるのでWorkManagerやAlarmManagerで更新を管理すること、RemoteViewsは使えるViewに制限があるのでカスタム描画は別途工夫が要ること、ウィジェットのリサイズや複数サイズ対応を忘れないことです。
テストは実機で表示やタップ動作を必ず確認してください。ログを細かく出しつつ最小の機能から積み上げるとバグが早く潰せます。気軽に試して、使いやすさを意識した細かい改善を繰り返してみてください。
