backend
Android WorkManager 완벽 가이드 — 백그라운드 작업 스케줄링 실전
Android WorkManager로 신뢰성 있는 백그라운드 작업을 구현하는 방법을 제약 조건 설정, 주기적 작업, 작업 체이닝, 진행 상태 관찰까지 실전 예제로 정리하였다.
- ·WorkManager는 앱 종료나 기기 재시작 후에도 작업이 재실행되도록 보장한다
- ·PeriodicWorkRequest의 최소 반복 주기는 15분이다
- ·WorkManager는 내부적으로 API 수준에 따라 JobScheduler, AlarmManager, Firebase JobDispatcher를 선택한다
- ·Constraints로 네트워크 연결, 충전 중, 배터리 여유 조건을 지정할 수 있다
이미지 업로드 기능에서 ForegroundService를 직접 구현했다가 백그라운드 제한 정책 변화로 Android 12 이상에서 오류가 발생했다. WorkManager로 전환하자 OS가 알아서 적절한 시점에 작업을 실행해줘 예외 처리 코드가 절반으로 줄었고, 기기 재시작 후 업로드가 자동 재개되는 기능도 추가 코드 없이 무료로 얻었다.
WorkManager Worker 구현과 기본 설정
Android WorkManager CoroutineWorker로 비동기 백그라운드 작업 구현하기
WorkManager 작업은 Worker 또는 CoroutineWorker를 상속해 doWork() 메서드를 구현한다. 코루틴을 사용하는 프로젝트라면 CoroutineWorker를 선택하면 doWork()가 suspend 함수로 선언되어 비동기 작업을 자연스럽게 작성할 수 있다. 작업 성공 시 Result.success(), 재시도 필요 시 Result.retry(), 최종 실패 시 Result.failure()를 반환한다. inputData로 작업에 데이터를 전달하고 outputData로 결과를 반환받는다. 단, Data 객체는 10KB 한도가 있으므로 대용량 데이터는 파일이나 데이터베이스를 경유해야 한다. setForeground()를 호출해 알림을 연결하면 장시간 작업을 포그라운드 서비스로 실행해 OS가 강제 종료하지 않도록 할 수 있다.
class UploadWorker(ctx: Context, params: WorkerParameters) :
CoroutineWorker(ctx, params) {
override suspend fun doWork(): Result {
val uri = inputData.getString(KEY_URI) ?: return Result.failure()
return try {
uploadRepository.upload(uri)
Result.success()
} catch (e: IOException) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}Android WorkManager 제약 조건과 주기적 작업 설정 방법
OneTimeWorkRequest는 단발성 작업에, PeriodicWorkRequest는 반복 작업에 사용한다. 제약 조건은 Constraints.Builder()로 작성하며 setRequiredNetworkType(NetworkType.CONNECTED), setRequiresCharging(true), setRequiresBatteryNotLow(true) 등을 조합할 수 있다. 모든 제약이 충족될 때만 작업이 실행되며, 조건이 해소될 때까지 작업은 대기 상태로 유지된다. PeriodicWorkRequest는 최소 15분 간격으로 설정할 수 있으며, 정확한 실행 시각보다는 지정한 간격의 flex 윈도우 안에서 배터리 최적화를 고려해 실행된다. 정확한 시각이 중요한 알림 작업이라면 AlarmManager를 쓰고, 네트워크나 배터리 조건이 중요한 데이터 동기화라면 WorkManager가 적합하다.
WorkManager 작업 체이닝과 상태 관찰
Android WorkManager 작업 체이닝으로 순차·병렬 백그라운드 파이프라인 구성하기
WorkManager.getInstance(context).beginWith(workA).then(workB).enqueue() 형태로 작업을 순차 체인으로 연결할 수 있다. workA가 성공해야만 workB가 시작되며, workA가 실패하면 이후 체인 전체가 실행되지 않는다. 병렬로 여러 작업을 동시에 실행하고 모두 완료 후 다음 단계로 넘어가려면 WorkContinuation.combine(listOf(workA, workB)).then(workC)를 사용한다. 작업 간 데이터 전달은 outputData와 inputMerger로 이루어지며, ArrayCreatingInputMerger를 사용하면 여러 병렬 작업의 결과를 배열로 합쳐 다음 작업에 전달할 수 있다. 실제 이미지 처리 파이프라인에서 다운로드 → 리사이즈 → 워터마크 → 업로드 순서로 체인을 구성했더니 각 단계의 재시도 로직이 WorkManager에 위임되어 코드가 훨씬 단순해졌다.
WorkManager 작업 상태 관찰과 디버깅
Android WorkManager LiveData와 Flow로 백그라운드 작업 진행 상태 실시간 관찰하기
WorkManager.getWorkInfoByIdLiveData(workRequest.id) 또는 getWorkInfoByIdFlow()로 작업 상태를 실시간 관찰할 수 있다. WorkInfo.State 열거형이 ENQUEUED → RUNNING → SUCCEEDED 또는 FAILED 순으로 변경되며 UI에서 진행 상황을 표시하기에 적합하다. Worker 내부에서 setProgress(workDataOf(KEY_PROGRESS to 50))를 호출하면 실행 중 진행률을 전달할 수 있다. 디버깅 시에는 adb shell dumpsys jobscheduler나 Android Studio의 Background Task Inspector를 활용하면 등록된 작업 목록과 상태를 시각적으로 확인할 수 있다. 테스트 환경에서는 WorkManagerTestInitHelper.initializeTestWorkManager()와 SynchronousExecutor를 사용해 작업이 동기적으로 실행되도록 설정하면 단위 테스트가 가능해진다.
자주 묻는 질문
WorkManager 작업이 등록 후 바로 실행되지 않는 이유는 무엇인가요?+
배터리 최적화와 제약 조건 충족 여부에 따라 지연될 수 있습니다. 테스트 시에는 TestDriver.setAllConstraintsMet()으로 제약 조건을 즉시 만족시킬 수 있습니다.
WorkManager와 ForegroundService 중 언제 무엇을 사용해야 하나요?+
즉각적인 사용자 인지가 필요한 작업(음악 재생, 통화 녹음)은 ForegroundService, 조건이 충족될 때 실행되면 되는 신뢰성 높은 작업(업로드, 동기화)은 WorkManager가 적합합니다.
WorkManager에서 특정 작업만 취소하려면 어떻게 하나요?+
enqueueUniqueWork로 등록할 때 지정한 고유 이름으로 cancelUniqueWork(uniqueName)을 호출하거나, workRequest.id로 cancelWorkById()를 호출합니다.