Android Jetpack 아키텍처의 구성 요소 중 하나로 안드로이드의 백그라운드 작업을 처리하는 방법이다.
앱이 종료되거나 기가가 다시 시작되어도 실행 예정인 지연 가능한 비동기 작업을 쉽게 예약할 수 있게 해준다.
하나의 코드로 API Level 마다 비슷한 동작을 보장한다.
WorkerManager 구성요소
Worker
백그라운드에서 수행될 테스크를 의미
추상 클래스인 Worker를 상속한 클래스를 구현하고 Override 되는 doWork() 메소드 안에 동작할 테스크를 구현해야 한다.
WorkRequest
WorkManager에 수행할 테스크를 요청할 때 사용되는 클래스
수행할 Worker를 등록해야 하고, 한번만 실행할 것인지 주기적으로 실행할 것인지 설정할 수 있다.
OneTimeWorkRequest - 단순 실행, PeriodicWorkRequest - 반복실행
WorkManager
WorkManager에 WorkRequest들이 추가되며, 설정에 맞게 테스크를 동작 시킨다.
WorkInfo
WorkManager에 추가된 테스크들의 상태를 나타낸다.
Enqueue, Running, Success, Fail 등의 테스크의 현재 상태를 알 수 있다.
WorkManager는 WorkInfo를 LiveData로 제공하기 때문에 Observer를 붙여 상태를 감시할 수 있다.
사용 예시
Worker 생성 - doWork() 메소드 안 처리할 계산을 넣고 결과에 따라 조건문을 다르게 주어 Result 값을 다르게 return 할 수 있다
class SimpleWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
val number = 11
val result = number * number
SystemClock.sleep(3000)
Log.d("SimpleWorker", "SimpleWorker finished : $result")
return Result.success() //Success, failure, retry
}
}
버튼을 누르면 생성한 Worker를 실행 시키는 코드이다.
startSimpleWorkerBtn.setOnClickListener {
//단일 request
val simpleRequest = OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()
//반복 request, 여러가지 시간대 설정가능 MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS 등등
val repeatRequest = PeriodicWorkRequestBuilder<SimpleWorker>(15, TimeUnit.MINUTES).build()
//WorkManager에 Request 추가
val workManager = WorkManager.getInstance()
workManager.enqueue(simpleRequest)
//WorkManager로부터 getWorkInfoLiveData로 request의 WorkInfo로 가져옴
val workInfo = workManager.getWorkInfoByIdLiveData(simpleRequest.id)
//Observer 연결로 실시간 WorkInfo 처리가 가능
workInfo.observe(this, Observer<WorkInfo> { info ->
val workFinished = info.state.isFinished
simpleWorkStatusText.text = when (info.state) {
WorkInfo.State.SUCCEEDED,
WorkInfo.State.FAILED -> { "세미나 work 진행상태: ${info.state}\n진행성공유무: $workFinished" }
else -> { "세미나 work 진행상태: ${info.state}\n진행성공유무: $workFinished" }
//State 태스크의 상태 RUNNING,SUCCEEDED,FAILED,ENQUEUED,BLOCKEDCANCELLED
}
})
}
Request를 만들때 반복 Request에서는 여러가지 시간대 설정이 가능하다.
결과
Fucntion
InputData, OutputData
InputData로 Worker에 put변수형을 해줄 경우, 원하는 data를 Worker 안에서도 사용이 가능
val inputData = Data.Builder().putInt("input", 5).build()
val simpleRequest = OneTimeWorkRequest.Builder(SimpleWorker::class.java)
.setInputData(inputData)
.build()
마찬가지로 Worker에서 outputData를 사용해 밖으로 값을 전달할 수 있다.
class SimpleWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
val result = inputData.getInt("input",0) + 11
val outputData = Data.Builder().putInt("output", result).build()
return Result.success(outputData)
}
}
Cancel
WorkManager를 통해 모든 태스크를 취소하거나 또는 특정 ID나 TAG를 갖고 있는 태스크를 취소할 수 있다. cancelAllWorkByTag, cancelWorkById, cancelAllWork 등을 사용할 수 있다
cancelWorkerBtn.setOnClickListener {
workManager.cancelWorkById(simpleRequest.id)
}
Constraints
Constraints.Builder를 통해 WorkRequest에 여러 제약조건을 가지는 작업을 수행하게 할 수 있다.
- .setRequiredNetworkType(NetworkType.CONNECTED) //네트워크 연결상태
- .setRequiresCharging(true) //충전 중
- .setRequiresBatteryNotLow //배터리가 적지 않을 때
val constraints = Constraints.Builder()
.setRequiresCharging(true) // 디바이스가 충전 중일때만 가능
.setTriggerContentMaxDelay(9,TimeUnit.MINUTES) //콘텐츠 변경이 처음 감지된 후부터 작업이 예약될 때까지 허용되는 최대 총 지연 시간(밀리초)을 설정
.setRequiresDeviceIdle(true) //작업 요청을 실행하기 위해 디바이스를 유휴 상태로 둘지 여부 설정
.build()
val simpleRequest = OneTimeWorkRequest.Builder(SimpleWorker::class.java)
.setInputData(inputData)
.setConstraints(constraints)
.build()
Chaining Task
WorkManager는 여러 Task를 순차적으로 실행할 수 있도록 기능을 제공한다.
가장 먼저 실행되는 Task는 WorkManager.beginWith 으로 설정하고, 그 다음 실행되는 Task는 WorkManager.then 으로 설정 할 수 있다.
WorkManager.getInstance()
.beginWith(TASK!, TASK2, TASK3)
.then(TASK4)
.then(TASK5, TASK6)
.enequeue()
chain 적용
val simpleRequest = OneTimeWorkRequest.Builder(SimpleWorker::class.java)
.setInputData(inputData)
.build()
val simpleRequest2 = OneTimeWorkRequest.Builder(SimpleWorker2::class.java).build()
val simpleRequest3 = OneTimeWorkRequest.Builder(SimpleWorker3::class.java).build()
val workList = mutableListOf<OneTimeWorkRequest>(simpleRequest2,simpleRequest3)
workManager
.beginWith(workList)
.then(simpleRequest)
.enqueue()
Chaining Policy
체이닝 정책
백그라운드 작업 관리를 할 때 구현에 따라 중복 되지 않아야 하는 상황에서는 같은 작업이 이미 있는지 파악해야 하고, 새 작업으로 대체해야 한다면 이전 작업을 취소해야한다.
또는 이미 추가된 작업 이후 또 다른 작업이 되어야 하는 경우는 이전 작업이 끝날때까지 상황을 추적하여 종료시점에 다시 작업을 추가 해야한다.
이런 케이스들을 위해 WorkManager는 beginUniqueWork() 로 작업에 유일한 이름을 부여하고 이 이름을 통해서 큐에 넣거나, 조회하거나, 취소 할 수 있다.
부여할 이름, Policy(관리정책), 관리 할 워커 를 넣고 실행한다.
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, simpleRequest).enqueue()
Policy의 종류로 KEEP, REPLACE, APPEND, APPEND_OR_REPLACE가 있다.
KEEP
같은 이름을 가지는 작업 A가 대기중이거나 실행 중이면 작업B는 큐에 추가되지 않음. 작업B 실행 시 A의 실행이 이미 끝났다면 B가 큐에 추가 됨.
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, downTask1).enqueue()
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, downTask2).enqueue()
REPLACE
작업A를 취소하고 작업B를 큐에 추가 작업A가 이미 끝난 상태라면 둘다 실행됨
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, downTask1).enqueue()
workManager.beginUniqueWork("sync", ExistingWorkPolicy.REPLACE, downTask2).enqueue()
APPEND
작업B를 BLOCKED 상태로 대기, A작업이 완료되면 B를 큐에 추가
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, downTask1).enqueue()
workManager.beginUniqueWork("sync", ExistingWorkPolicy.APPEND, downTask2).enqueue()
이전 작업(A)이 취소처리나 실패 되면 이후 작업도 취소, 실패 처리 됨
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, downTask1).enqueue()
workManager.cancelUniqueWork("sync")
workManager.beginUniqueWork("sync", ExistingWorkPolicy.APPEND, downTask2).enqueue()
APPEND_OR_REPLACE
APPEND 와 동일하게 BLOCKED 상태로 대기하나 이전 작업이 실패, 취소되어도 새 작업을 실행
workManager.beginUniqueWork("sync", ExistingWorkPolicy.KEEP, downTask1).enqueue()
workManager.cancelUniqueWork("sync")
workManager.beginUniqueWork("sync", ExistingWorkPolicy.APPEND_OR_REPLACE, downTask2).enqueue()
'Android > Reference' 카테고리의 다른 글
AAC (Android Architecture Component) (1) | 2022.02.07 |
---|---|
string.xml 에 %d, %s 사용 / Databinding 에 StringFormat 적용 (0) | 2022.01.20 |
View invalidate(), requestLayout() 의 차이 (0) | 2021.12.22 |
Scroll 상, 하단바 숨기기 (CoordinatorLayout) (0) | 2021.12.16 |
ClickCountListener (특정횟수 클릭 리스너) (0) | 2021.12.10 |