導入:バックグラウンド処理は「API選び」でほぼ決まる
Androidのバックグラウンド処理は、実装方法を間違えると将来的に必ず壊れます。
AlarmManager、Service、WorkManager。
選択肢は多いですが、どれも同じ用途ではありません。
「動いているからOK」という判断で選ぶと、OSアップデートや端末依存の問題に巻き込まれがちです。
この記事では、WorkManagerを基準にしながら、Alarm / Service とどう使い分けるべきかを整理します。
先に結論です。
- 確実に実行したい処理は WorkManager
- 即時性が最優先なら Service
- 時刻トリガーだけ必要なら AlarmManager
まず考えるべきは「処理の性質」
APIを選ぶ前に、処理の性質を言語化する必要があります。
- 必ず実行される必要があるか
- 多少遅れても問題ないか
- ユーザー操作と直接結びついているか
- アプリが落ちても継続すべきか
これを整理せずにAPIを選ぶと、設計はほぼ確実に破綻します。
Serviceの役割と限界
Serviceは「バックグラウンド処理」という言葉から想像されがちですが、
実態はフォアグラウンド寄りの仕組みです。
Serviceの特徴
- 即時に処理が開始される
- アプリプロセスと強く結びつく
- 長時間実行には厳しい制限がある
Serviceが適している処理
- 音楽再生
- ナビゲーション
- ユーザーが明示的に開始・停止する処理
逆に、「いつか実行されればいい処理」には向きません。
AlarmManagerは「実行」ではなく「合図」
AlarmManagerは、指定時刻に何かを起動するための仕組みです。
AlarmManagerの特徴
- 時刻ベースのトリガー
- 正確性は省電力機構の影響を受ける
- 実処理は別途用意する必要がある
AlarmManagerが向いている場面
- 通知の時刻指定
- カレンダー・リマインド系
AlarmManagerは処理を実行する仕組みではありません。
この点を誤解すると、設計が複雑化します。
WorkManagerは「確実性」を最優先した設計
WorkManagerは、処理が必ず実行されることを最優先に設計されています。
WorkManagerの特徴
- アプリ終了・端末再起動後も実行される
- ネットワーク・充電状態などの制約指定
- OSに応じて内部実装を自動切替
開発者は「どう実行するか」を考えず、
「何をしたいか」だけを定義します。
最小構成の実装例
Workerの定義
class SampleWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// バックグラウンド処理
return Result.success()
}
}
Workの登録
val request = OneTimeWorkRequestBuilder().build()
WorkManager.getInstance(context)
.enqueue(request)
これだけで、OSに最適な方法で処理が実行されます。
WorkManagerが壊れにくい理由
制約ベース実行
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
条件が揃うまで待つ設計が、
バッテリー消費と安定性を両立します。
失敗前提の設計
return Result.retry()
「失敗しても再実行される」ことを前提にできるのは、
ServiceやAlarmにはない強みです。
API選択の指針まとめ
WorkManagerを選ぶべき処理
- ログ送信
- データ同期
- バックアップ
Serviceを選ぶべき処理
- 即時性が必須
- ユーザー操作と強く連動
AlarmManagerを選ぶべき処理
- 時刻トリガーが目的
よくあるアンチパターン
- すべてServiceで実装する
- Alarmで重い処理を直接実行する
- WorkManagerを即時実行用途で使う
テスト・運用時の注意
- 即時実行される前提で設計しない
- 再実行されても問題ない処理にする
- 途中でアプリが落ちても破綻しないか確認
まとめ
- バックグラウンド処理は目的で選ぶ
- 確実性が必要ならWorkManager
- 迷ったらまずWorkManagerで設計する
迷ったら:確実性を優先する。
それが一番壊れにくい判断です。

コメント