[Android] WorkManager
백그라운드에서 작업을 실행하면 RAM 및 배터리와 같은 제한된 리소스가 소모됩니다.
따라서, 배터리 수명을 개선하고 더 나은 사용자 경험을 제공하기 위해 백그라운드 실행에 대한 제한을 설정합니다.
- 잠자기 및 앱 대기
- 화면이 꺼져있고, 기기가 유휴 상태이고 충전중이 아닌 경우
- 백그라운드 위치제한
- 백그라운드 앱이 사용자의 현재 위치를 검색할 수 있는 빈도를 제한
- 백그라운드 서비스 제한
- 백그라운드 서비스가 실행되고 숨겨지거나 보이지 않는 방식으로 소비하지 못하도록 제한
- 응용프로그램 제한
개요
- 지연 가능한 비동기 작업을 쉽게 예약할 수 있는 API
- 작업을 즉시 실행할 필요가 없는 경우
- 분석 데이터를 서버로 보내는 경우, 백그라운드에서 데이터베이스 동기화 작업 등등..
- 보장된 실행을 제공
- 앱이 종료되거나 기기가 다시 시작되더라도 작업이 실행
백그라운드 실행 방법
사용사례 | 예 | 해결책 |
연기 가능한 작업 실행보장 | 서버에 로그 업로드 다운로드 / 업로드 콘텐츠 암호화/ 복호화 데이터베이스 동기화 |
WorkManager |
외부 이벤트에 대한 응답으로 시작된 작업 | 이메일과 같은 온라인 콘텐츠 동기화 | FCM + WorkManager |
앱을 종료하더라도 즉시 실행해야하는 작업 | 음악플레이어 활동 추적 네비게이션 |
Foreground Service |
정확한 시간에 알림과 같이 사용자 상호 작용과 관련된 작업을 트리거 | 알람 시계 의학 알림 |
AlarmManager |
기능
- 작업 제약조건
옵션 | 설명 |
NetworkType | 작업이 필요한 네트워크 유형을 제한합니다. |
BatteryNotLow | 기기의 배터리 부족모드인경우 작업을 제한여부를 설정합니다. |
RequiresCharging | 기기가 충전중인 경우에만 작업을 실행할 여부를 설정합니다. |
DeviceIdle | 기기가 유휴상태에서만 작업할 여부를 설정합니다. |
StorageNotLow | 기기의 저장공간이 부족한 경우 작업할 여부를 설정합니다. |
NetworkType의 종류
옵션 | 설명 |
CONNECTED | 네트워크가 연결되어있는 경우 |
UNMETERED | 무제한 네트워크에 연결되어있는경우 ex) Wifi |
METERED | 데이터 통신망에 연결되어있는경우 |
NOT_REQUIRED | 네트워크가 필요없는경우 |
NOT_ROAMING | 비 로밍 네트워크가 연결이되어있는경우 |
사용방법
private fun createConstraints() : Constraints{
return Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
setRequiresDeviceIdle(true)
}
.setRequiresStorageNotLow(true)
.build()
}
- 강력한 예약 관리
주기적 실행
private fun createWorkManager(){
val periodicWorkRequest = PeriodicWorkRequestBuilder<Worker>(1, TimeUnit.DAYS).build()
WorkManager.getInstance(applicationContext).enqueueUniqueWork("work", ExistingWorkPolicy.KEEP, periodicWorkRequest)
}
- 하루마다 실행하도록 구성됨
- enqueueUniqueWork로 워크 매니저에 등록
- UniqueWorkName, 같은 이름을 가진다면 정책을 정하고, Request를 넣어준다.
일회성 실행
private fun createWorkManager(){
val oneTimeWorkRequest = OneTimeWorkRequestBuilder<Worker>().build()
WorkManager.getInstance(applicationContext).enqueueUniqueWork("A", ExistingWorkPolicy.KEEP, oneTimeWorkRequest)
}
정책
옵션 | 설명 |
APPEND | 동일한 고유이름을 가지고 완료되지않은 작업이 있다면 추가한다. |
APPEND_OR_REPLACE | 동일한 고유이름을 가지고 완료되지않은 작업이 있다면 추가한다. |
KEEP | 동일한 고유이름을 가지고 완료되지않은 작업이 있다면 아무런 일을 하지않는다. |
REPLACE | 동일한 고유이름을 가지고 완료되지않은 작업이 있다면 취소하고 삭제한뒤 실행한다. |
- 유연한 재시도 정책
- 경우에 따라 작업을 실패할 때도 있기 때문에 해당 내용을 재실행할 수 있다.
재시도 정책
옵션 | 설명 |
Result.success() | 작업이 성공적으로 완료되었습니다. |
Result.failure() | 작업에 실패하였습니다. |
Result.retry() | 재시도 정책에 따라 다른시점에 시도 |
class Worker(appContext: Context, parameters: WorkerParameters) : CoroutineWorker(appContext, parameters) {
override suspend fun doWork(): Result {
try {
//Work
}catch (e: Exception){
Result.retry()
}
return Result.success()
}
}
- 작업 체이닝
- 복잡한 작업인 경우 인터페이스를 이용하여 순차적으로 동작하게 할 수 있다.
WorkManager.getInstance(...)
.beginWith(listOf(workA,workB))
.then(workC)
.enqueue()
- 내장 스레딩 상호 운용성
- RxJava, Coroutine 등을 사용할 수 있다.
위의 내용을 통해서 wifi를 이용해야 하며, 배터리가 부족하면 안 되고, 충전 중이여 야만 하고, 저장공간이 충분한 경우, 진행 중인 작업이 있는 경우는 작업을 하지 않는 일회성 작업을 구성하는 내용은 아래와 같이 구성할 수 있다.
Work.class
class Worker(appContext: Context, parameters: WorkerParameters) : CoroutineWorker(appContext, parameters) {
companion object{
const val WORK_NAME = "Notification Work"
}
override suspend fun doWork(): Result {
try {
//Work
}catch (e: Exception){
Result.retry()
}
return Result.success()
}
}
Application클래스가 가장 먼저 생성되기 때문에 Application의 onCreate에서 작업을 해준다.
class WorkApplication : Application() {
private val backgroundCoroutineScope = CoroutineScope(Dispatchers.Default)
override fun onCreate() {
super.onCreate()
delayCreateWork()
}
private fun delayCreateWork(){
backgroundCoroutineScope.launch {
createWorkManager()
}
}
private fun createWorkManager(){
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.setRequiresStorageNotLow(true)
.build()
val oneTimeWorkRequest = OneTimeWorkRequestBuilder<Worker>().
setConstraints(constraints).build()
WorkManager.getInstance(applicationContext).enqueueUniqueWork(Worker.WORK_NAME, ExistingWorkPolicy.KEEP, oneTimeWorkRequest)
}
}
코 루틴을 이용한 이유는, onCreate에서 바로 실행을 하게 되면 기본 스레드에서 실행이 되기 때문에 앱 로드가 지연되거나 UI스레드가 차단될 수 있기 때문에 사용해주는 것이 좋다.
※ 참고사이트
https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html
Modern background execution in Android
Posted by Luiz Gustavo Martins, Partner Developer Advocate, Partner DevRel This is the third in a series of blog posts in which outli...
android-developers.googleblog.com
Android Kotlin Fundamentals: WorkManager | Android 개발자
In this codelab, you learn how to use WorkManager to schedule background tasks in an efficient and optimized way in your Android Kotlin app.
developer.android.com
https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko
WorkManager로 작업 예약 | Android 개발자 | Android Developers
WorkManager로 작업 예약 Android Jetpack의 일부 WorkManager는 지연 가능한 비동기 작업을 쉽게 예약할 수 있는 API로, 지연 가능한 비동기 작업은 앱이 종료되거나 기기가 다시 시작되더라도 실행될 것
developer.android.com