안드로이드 세계

[Android] WorkManager 본문

안드로이드(Android)/코틀린(Kotlin)

[Android] WorkManager

리안94 2021. 5. 31. 23:15

백그라운드에서 작업을 실행하면 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

https://developer.android.com/codelabs/kotlin-android-training-work-manager?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fkotlin-fundamentals-nine%23codelab-%2Fcodelabs%2Fkotlin-android-training-work-manager#0 

 

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

 

Comments