728x90
🗒 WorkManager 이론
📌 안드로이드의 백그라운드 작업
- 실행 시점에 다른 분류
- Exact Timing : 즉시 처리되어야 하는 작업
- Deferrable : 처리를 위한 조건이 만족될 때까지 기다릴 수 있는 작업
- 실행 완료 여부에 따른 분류
- Best-Effort : 처리를 위해 노력하지만 취소될 수도 있는 작업
- Guranteed Execution : 앱이 종료되거나 기기가 재부팅되어도 수행되어야 하는 작업
- 안드로이드에는 위 표처럼 이미 백그라운드 Task를 처리하기 위한 많은 라이브러리들이 존재한다.
- WorkManager는 이 중에서 Defferd와 Guaranteed Execution의 작업들을 대체하기 위해서 탄생하였다.
- 그렇다면 이미 라이브러리가 존재하는데 왜 구글은 WorkManger를 새로 만든 것일까?
그 이유를 알기 위해 안드로이드 백그라운드 API 변천 과정을 살펴보자
📌 안드로이드 백그라운드 API 변천 과정
- API 18 : AlarmManager
- 안드로이드 API 18까지는 시스템에 Broadcast Receiver를 등록하고 앱에서 AlarmManger로 알람을 전달하면 호출되는 Service로 백그라운드 작업을 수행하였다.
- API 19 : AlarmManager(X)
- 그런데 API 19부터는 기기의 WakeUp Alarm과 배터리 소모를 최소화하기 위해 시스템이 알람 타이밍을 변경할 수 있게 되었다.
- 따라서 이러한 AlarmManager가 더이상 정확한 시간에 동작하는 것을 보장할 수 없게 되었다.
- Google I/O 2014 - JobScehduler (Project Volta 중 하나)
- 이러던 와중에 구글은 2014 Google I/O에서 Project Volta를 발표한다.
- 이 중에 JobScehduler라는 것이 소개되었는데 이 JobScehduler는 백그라운드 작업의 실행 타이밍을 앱이 아닌 시스템이 판단하게 함으로써 배터리 시간을 갉아먹는 무분별한 백그라운드 작업을 제한한다.
- 발표에 따르면 AlarmManager에 비해서 약 25% 정도의 배터리개선 효과를 내었다고 한다.
- 그 이후로도 구글은 백그라운드 작업을 제한하는 정책을 지속해서 내게 된다.
- API 23 : Doze and App Standby
- API 24 : Doze on-the-go, Limited implicit broadcasts API
- API 26 : Background service limitations, Implicit Broadcast Exceptions, Release cached wakelocks
- API 28 : App Standby Buckets, Battery Saver mode
- API 29 : Restrictions on starting activities
- API 30 : Background location access
- API 31 : Foreground service launch restrictions, Phantom Processes
📌 WorkManager의 발표
그러던 와중 Google I/O 2018에서 WorkManger가 발표된다.
- Guranteed, constraint-aware execution
- 실행이 보장되며 제약조건을 붙일 수 있다.
- 예를 들면 네트워크 연결시에만, 혹은 기기가 충전 중 일 때만 작업이 처리되도록 할 수 있다.
- Respectful of system background restrictions
- 장치의 상태를 존중한다.
- 예를 들면 앱이 도즈모드일 경우 작업 처리를 위해 기기를 깨우지 않는다.
- Backwards compatible with or without Google Play Services
- 구글 플레이 서비스와 관계 없이 동작한다.
- Queryable
- 작업이 실행 혹은 대기중인지? 성공 혹은 실패했는지 등의 상태 조회를 할 수 있다.
- Chainable
- 작업 A, B 결과에 따라 처리되는 작업 C를 만들고, 다시 작업 C 결과에 의존하는 작업 D를 만들 수 있다.
- Opportunisitic
- 사용자를 간섭하지 않아도 제약조건이 만족되면 작업이 즉시 실행된다.
📌 WorkManger의 동작 구조
- 그림과 같이 시스템에 따라서 적절한 백그라운드 API를 선택하도록 설계되어있다.
- API 23보다 높은가?
- 그렇다 : JobSceduler 사용
- 아니다 : Firebase JobDispatcher 포함 여부로 이동
- Firebase JobDispatcher를 포함하고 있는가?
- 그렇다 : Firebase JobDispatcher 사용
- 아니다 : AlarmManager와 Broadcast Receivers 사용
- API 23보다 높은가?
📌 구글에서 제안하는 Use Case
- WorkManger는 만능 라이브러리가 아니다.
- Defferable & Guaranteed Excution 한, 즉 처리를 위한 조건이 만족될 때까지 기다릴 수 있는 작업 & 앱이 종료되거나 기기가 재부팅되어도 수행되어야 하는 작업, 두 가지 조건을 만족하는 작업을 위해 설계되었다
- 구글은 다음과 같은 Use Case를 제안한다.
구글이 제안하는 예시에서 WorkManger를 사용하는 경우는 로그를 서버에 업로드하는 경우라던지 암호화, 복호화된 콘텐츠를 업로드 혹은 다운로드할 때 혹은 새로운 온라인 이메일을 싱크 할 때 사용하라고 제안하고 있다.
💻 코드 예제 (실습)
📌 의존성 추가
dependencies {
def work_version = "2.71"
// java 를 사용한다면 다음의 줄을 추가
implementation "android.arch.work:work-runtime:$work_version"
// kotlin 을 사용한다면 다음의 줄을 추가
implementation "android.arch.work:work-runtime-ktx:$work_version"
// Firebase JobDispatcher 를 사용하려면 다음의 줄을 추가
implementation "android.arch.work:work-firebase:$work_version"
}
- 글을 포스팅하는 시점의 Stable version은 2.71이다.
- 버전은 지속적으로 올라갈 수 있다.
📌 Worker 작업 정의
class UploadWorkder(
appContext: Context,
workerParams: WorkerParameters
): Worker() {
override fun doWork(): Result {
// 이곳에서 작업을 수행
// 이 경우에는 uploadImage 함수를 수행한다.
uploadImages()
// 작업이 성공적으로 끝났는지 여부를 정의
return Result.success()
}
}
📌 제약조건 설정
- NetworkType
- 네트워크 여부가 필요한지 제약조건을 설정
- BatteryNotLow
- true로 설정되어 있다면 기기의 배터리가 낮다고 판단되면 작업이 수행되지 않는다.
- RequiresCharging
- true로 설정되어 있다면 기기가 충전중일때만 작업이 수행된다.
- Deviceldle
- true로 설정되어 있다면 작업이 수행되기 전에 장치가 idle(유휴 상태, 프로세스가 실행하고 있지 않은 상태)이어야 한다.
- 이 기능은 기기에서 활발하게 실행되는 다른 앱에 부정적인 영향을 미칠 수 있는 작업을 일괄적으로 실행하는 데 유용할 수 있다.
- StorageNotLow
- true로 설정되어 있다면 기기의 저장공간이 너무 낮다고 판단되면 작업이 수행되지 않는다.
📌 WorkRequest 만들기
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
val uploadWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(constraints)
.build()
- WorkRequest를 통해서 위의 Worker 클래스에서 정의한 작업을 어떠한 형태로 수행할지 정의한다.
- PeriodWorkRequest를 통해 주기적으로 수행되도록 하거나, OneTimeWorkRequest를 통해 단 한번만 수행되게 예약을 할 수 있다.
- 위 코드는 네트워크 타입과 충전 상태에 대한 제약조건을 설정하고 한 번만 수행되도록 WorkRequest를 만든 예시이다.
📌 WorkRequest 제출
WorkManager
.getInstance(myContext)
.enqueue(uploadWorkRequest)
- 제출된 WorkRequest는 WorkManager 내부의 Database에서 관리된다.
- Database는 작업 내용, 작업의 현재 상태, 작업의 제약조건 등이 포함된다.
- Contraints met 즉 제약조건이 만족되면 내부의 TaskExcutor에 의해서 작업이 실행되는 구조를 가지고 있다.
📌 Work States 확인하기
// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
- WorkRequest를 큐에 추가하고 나면 id, name 혹은 tag를 통해 언제든 Work State 즉 작업 상태를 확인할 수 있다.
Work State
1회성 작업
- ENQUEUED
- RUNNING
- SUCCEEDED
- FAILED
- CANCELLED
주기적 작업
- ENQUEUED
- RUNNUG
- CANCELLED
'Android' 카테고리의 다른 글
안드로이드 [Kotlin] - 프로젝트에 의존성 주입(DI) 적용해보기 - Hilt (0) | 2022.11.10 |
---|---|
안드로이드 [Kotlin] - 의존성 주입(DI) 알아보기 - Hilt (0) | 2022.11.07 |
안드로이드 [Kotlin] - ViewModel 파헤쳐보기 (0) | 2022.10.03 |
안드로이드 [Kotlin] - Task와 Launch Mode 그림으로 이해하기 (2) | 2022.09.20 |
안드로이드 [Kotlin] - Paging3 사용기 (Room 데이터, 네트워크 데이터) (0) | 2022.09.18 |