-
Android WorkManager 사용법Android 2021. 5. 4. 17:53
개요
안드로이드의 프로세스는 Foreground와 Background로 나뉩니다. Foreground는 유저가 앱과 화면에서 인터랙션을 할 수 있는 상태입니다. Background는 유저가 앱과 화면에서 인터랙션 하지않아도 실행되는 상태입니다.
앱을 종료하는 방식은 두가지 입니다. 뒤로가기 해서 종료하거나, 모두 보기에서 앱을 날리는 두가지 경우입니다. 여기서 뒤로가기를 해서 앱을 종료하는 경우는 프로세스를 완전히 종료하는 것이 아니라 Background로 남기는 것입니다. 반면 모두 보기를 해서 종료하면 프로세스 자체가 종료가 되는 것이죠.
다운로드를 하거나 음악을 실행시키는 것과 같이, 앱은 다양한 이유로 Background에서 Task를 실행합니다. 안드로이드에서는 이러한 Background Task 처리를 여러가지 방식으로 구현할 수 있는데, 대표적으로 Background Service와 Job Scheduler, WorkManager를 사용한 방법이 있습니다. 오늘은 WorkManager에 대해서 알아보겠습니다.
WorkManager 히스토리
WorkManager는 지연 될 수 있는 Background Task를 처리하기 위한 라이브러리인데, 여기서 지연된다는 것은 Task가 바로 실행되는 것이 아니라, 특정한 조건이나 상황에 맞을 때 실행될 수 있는, 즉 예약과 같은 상황을 말합니다. WorkManager는 다양한 API에 맞게 내부적으로 실행되는 방법이 틀린데요. 아래 이미지와 같이 API 23 이상부터는 JobScheduler, 그 이하는 GcmNetworkManager, AlarmManager 등을 통해 실행됩니다.
해당 도표에서 보시는 것처럼 Background Task 처리를 위한 다양한 기술들이 이미 있습니다. 하지만, GCM이나 FirebaseJobDispatcher는 구글 플레이 서비스가 지원되는 기기에서만 사용이 가능하다는 것과, Task를 실행되기전까지 계속 스케줄링하다보니 배터리 사용량이 늘어나는 문제가 있었습니다. 이러한 문제를 해결하기 위해 WorkManager가 나왔고, 배터리 효율성이 좀 더 우수하다는 것과, Task 스케줄링에 관한 여러 API를 제공해준다는 장점이 있습니다.
Android Developers Blog: Why WorkManager
Job Enqueue와 실행 방법
기본적으로 WorkManager를 통해 Job을 예약하고 실행시키기 위해선 세가지 객체를 사용해야합니다.
작업을 정의하는 Worker 클래스, 언제 어떻게 Worker를 생성하고, 실행할지에 대해 정의하는 WorkRequest, 그리고 WorkRequest를 Enqueue하는 WorkManager입니다.
각각의 클래스마다 여러가지 옵션이 있습니다. 특히 기본적인 작업 단위인 Worker는 동기적 호출만을 지원해서 비동기 호출 코드나 콜백에 대한 처리가 제대로 되지 않을 수 있습니다. 따라서, 비동기 호출 로직을 Worker에서 사용하기 위해서는 처리하기 위해서는 ListenableWorker와 RxWorker, CoroutineWorker를 사용해야합니다. 각 Worker마다 사용하는 기술들이 조금씩 다르기 때문에, 프로젝트의 기술 스택이나 상황에 따라 가장 적합한 Worker를 사용하면 되겠습니다.
WorkRequest는 알람처럼 주기적인 실행을 보장하는 PeriodicWorkRequest, 일회성 실행을 보장하는 OneTimeRequest로 사용할 수 있습니다.
class TestWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { var isProcessSuccess: Boolean = false if (!isProcessSuccess) { return Result.failure() } return Result.success() } }
Worker는 다음과 같이 반드시 doWork 메소드를 구현해야하고 내부 로직에 따라 Result.success 혹은 Result.failure를 반환해야합니다.
class TestWorkManager { lateinit var context: Context val workRequest: WorkRequest = OneTimeWorkRequestBuilder<TestWorker>().build() fun enqueueWorkRequest() { WorkManager.getInstance(context) .enqueue(workRequest) } }
정의한 Worker를 WorkRequestBuilder를 통해 인스턴스화하고, 이 workRequest 객체를 최종적으로 WorkManager에 enqueue함으로서 Job 예약을 완료합니다.
또, AndroidDevSummit에서 언급한 것처럼 WorkManager는 위의 도표와 같이 Database에 WorkRequest를 저장하는 것을 확인할 수 있습니다. 이러한 특성은 앱이나 기기의 종료와 상관없이 반드시 예약된 실행이 실행됨을 보장합니다.
Constraint를 통한 실행 조건 설정
개인적으로는 WorkManager의 가장 편리한 기능 중 하나라고 생각하는 Contraints입니다. WorkManager에서 백그라운드 작업을 실행시키기 위해선 실행 조건이 만족되야합니다.(이것이 Android의 백그라운드 처리에서 지연 가능한 백그라운드 작업과 관련이 있는 부분입니다)
WorkManager는 미리 정의된 실행 조건을 제공해주는데, 공식 메뉴얼에 자세하게 나와있습니다.
developer.android.com/reference/androidx/work/Constraints#requiresBatteryNotLow()
제공하는 실행 조건은 다음과 같습니다.
- requiresBatteryNotLow : 배터리가 낮지 않을 때 실행됩니다.
- requiresCharging : 기기가 충전 중일때만 실행됩니다.
- requiresDeviceIdle : 기기가 Idle 상태일 때 실행됩니다. Idle은 앱 대기 상태를 의미합니다.
- requiresStorageNotLow : 기기의 저장소가 여유가 있을 때만 실행됩니다.
- getRequiredNetworkType : 네트워크 값에 대한 설정을 줄 수 있습니다. (Wifi, Mobile Network)
val constraint = Constraints.Builder() .setRequiresBatteryNotLow(true) .setRequiredNetworkType(NetworkType.UNMETERED) .build() val workRequest: WorkRequest = OneTimeWorkRequestBuilder<TestWorker>() .setConstraints(constraint) .build()
실행 조건은 WorkRequest를 정의할 때, setConstraints 메소드를 통해 추가할 수 있습니다. 파라미터로 들어가는 constraint를 따로 정의해줘야합니다.
'Android' 카테고리의 다른 글
Android 12 - Notification trampoline restrictions (0) 2021.10.25 Two-way Binding 사용법 (0) 2020.12.22 onBackPressed와 finish의 차이 (0) 2020.12.04 Fragment에서 ViewBinding 사용 시 발생할 수 있는 메모리릭 (0) 2020.11.13 변수의 동시성 제어에 관한 이슈 및 해결 (1) 2020.10.27