WorkManager , 쉽게 쓰기

GM.Lim
9 min readJul 12, 2018

--

Photo by Sai Kiran Anagani on Unsplash

지난 포스트에서는 안드로이드의 백그라운드 작업 처리 방법의 변화 과정과 WorkManager 가 등장한 이유에 대해 알아보았습니다.

혹시 아직 읽어보지 않으셨다면 아래의 링크를 통해 읽어주세요.

이제 본격적인 사용법을 알아봅시다.

WorkManager 의 구성

WorkManager API 의 주요 클래스는 WorkManager, Worker, WorkRequest, WorkState 입니다.

  • WorkManager : 처리해야 하는 작업을 자신의 큐에 넣고 관리합니다. 싱글톤 인스턴트로 사용 하기 위해서 내부에 WorkManager 객체를 반환하는 getInstance() 함수가 있습니다. 이 메서드를 통해서 WorkManager 의 인스턴트를 받아 사용합니다.
  • Worker : 추상 클래스 입니다. 처리해야 하는 백그라운드 작업의 처리 코드를 이 클래스를 상속받아 doWork() 메서드를 오버라이드 하여 작성하게 됩니다.
    doWork() 메서드는 작업을 완료하고 결과에 따라 Worker 클래스 내에 정의된 enum 인 Result 의 값중 하나를 리턴해야 합니다. SUCCESS, FAILURE, RETRY 의 3개 값이 있으며 리턴되는 값에 따라 WorkerManager 는 해당 작업을 마무리 할것인지 재시도 할것인지, 실패로 정의하고 중단할것인지 이후 동작을 결정하게 됩니다.
  • WorkRequest : WorkManager 를 통해 실제 요청하게될 개별 작업입니다. WorkRequest 는 처리해야 할 작업인 Worker 와 작업 반복 여부 및 작업 실행 조건, 제약 사항 등 이 작업을 어떻게 처리할 것인지에 대한 정보가 담겨 있습니다. WorkRequest 는 반복 여부에 따라 다음의 두가지로 나뉘어 집니다.
  1. OneTimeWorkRequest : 반복하지 않을 작업, 즉 한번만 실행할 작업의 요청을 나타내는 클래스 입니다.
  2. PeriodicWorkRequest : 여러번 실행할 작업의 요청을 나타내는 클래스 입니다.
  • WorkState : WorkRequest 의 id 와, 해당 WorkRequest 의 현재 상태를 담는 클래스입니다. 개발자는 WorkState 의 상태 정보를 이용해서 자신이 요청한 작업의 현재 상태를 파악할수 있습니다. WorkState 는 ENQUEUED, RUNNING, SUCCEEDED, FAILED, BLOCKED, CANCELLED 의 6개의 상태를 가집니다.

직접 사용해 보면 쉽게 이해가 될테니 이제 예제와 함께 설명해 보겠습니다.

WorkManager 사용을 위한 의존성 추가

우선 안드로이드 프로젝트에 WorkManager 를 사용하기 위한 의존성 부터 추가합니다.

18년 7월 11일을 기준으로 WorkManager 의 최신버전은 1.0.0-alpha04 입니다. 프로젝트 모듈 의 build.gradle 의 dependencies 에 다음과 같이 추가합니다.

개발 언어로 자바 를 사용하신다면 필수1 번 줄을 , 코틀린 을 사용하신다면 필수2번 줄을 추가합니다. 참고로 이 포스트에서 예제는 모두 코틀린으로 작성 되었습니다.

만약 옵션 줄까지 추가한다면 WorkManager 는 현재 앱이 동작하는 기기의 버전 별 상황에 따라 적절한 작업 처리 방법으로 JobDispatcher 를 사용할수 있습니다.

JobDispatcher 는 구글 플레이 서비스에 의존성을 가지므로 구글 플레이 서비스에 대한 의존성을 사용할수 없는 환경 이거나 구글 플레이 서비스에 대한 의존성을 원하지 않는경우 추가하지 않아도 WorkManager 는 다른 방식을 이용하여 작업을 처리합니다.

사용법1. 단순 작업

기본적인 사용법은 매우 간단합니다.

  1. Worker 클래스를 상속받은 클래스를 만들고 doWork() 메서드를 오버라이드 합니다. 처리 결과에 따른 Result 값을 리턴해야 합니다.

2. OneTimeWorkRequestBuilder 를 이용해서 OneTimeWorkRequest 객체를 생성합니다. 이제 SimpleWorker 는 한번 실행 될수 있는 작업이 되었습니다.

OneTimeWorkRequestBuilder 는 코틀린을 위해 정의된 인라인 함수 이므로 자바를 사용하신다면 OneTimeWorkRequest 클래스 내에 정의된 OneTimeWorkRequest.Builder 를 사용하셔야 합니다.

3. WorkManager 클래스의 getInstance() 메서드로 싱글턴 객체를 받아서 WorkManager 의 작업 큐에 OneTimeWorkRequest 객체를 추가 하면 끝입니다.

다음은SimpleWorker 의 작업을 한번 수행하는 doWorkOneTime() 의 작성 예시 입니다.

이제 WorkManager 는 큐에 추가된 작업들을 관리하고, 각 작업자에 지정된 제약 조건을 지키면서도, 시스템의 자원을 과도하게 사용하지 않도록 관리하여 각 작업들을 예약합니다.

반복되는 작업은 PeriodicWorkRequestBuilder 를 이용하여 PeriodicWorkRequest 객체를 생성하여 WorkManager 의 큐에 추가 하면 됩니다. 이때 첫번째 인자로는 반복될 인터벌 값, 두번째 인자로는 이 인터벌의 시간타입이 필수로 들어가야 합니다. 다음과 같은 예시는 15분 반복을 뜻하며 TimeUnit 에정의된 다른 시간 타입 enum 을 사용할수도 있습니다.

반복 시간에 사용할수 있는 가장 짧은 최소값은 PeiodicWorkRequest 클래스 내의 MIN_PERIODIC_INTERVAL_MILLIS 상수로 정의되어 있으며 15분 보다 짧은 시간은 사용할수 없습니다.

PeriodicWorkRequestBuilder 역시 코틀린을 위한 인라인 함수로 자바를 사용하신다면 PeriodicWorkRequest 클래스 내의 PeriodicWorkRequest.Builder 를 사용하시면 됩니다.

사용법2. 제약 조건을 가지는 작업

WorkManager 는 제약 조건을 추가하여 작업을 실행할수 있습니다. 예를 들어내 작업이 네트워크가 연결된 환경에서만 수행될수 있는 작업이라면 이 조건을 추가하여 네트워크가 연결됐을때는 작업 처리를 수행하도록 할수 있습니다. 제약 조건은 다양하게 추가할수 있습니다.

이에 따라 WorkManager 는 해당 제약조건이 만족되면 작업을 수행하고, 조건이 만족되지 않으면 작업을 취소하며, 처리가 완료되지 못하고 실패 하였다면 제약조건이 만족되는 다음 타이밍에 다시 처리를 시도합니다.

제약조건은 Constraints 클래스의 Builder 를 이용하여 생성하여 WorkRequest 에 추가합니다. 이제 WorkRequest 는 처리해야 하는 작업과 함께 제약 조건의 정보를 가지게 됩니다. 이를 WorkManager 의 큐에 추가 하면 WorkManager 는 이제 제약 조건을 확인 하여 적당한 시기에 작업을 처리하게 됩니다.

다음은 네트워크 연결 상태 와 충전 상태 의 두가지 제약 조건을 가지는 한번만 수행되는 작업을 추가하는 예시 입니다.

사용법3. 연결된 작업 (Chaining work)

SNS 서비스에서 사용자가 사진을 올리는 케이스를 생각해 봅시다. 앱은 사진을 적당한 사이즈로 압축하고, 서버로 업로드 해야 합니다.

사진을 압축하는 작업을 compressWork, 업로드 하는 작업을 uploadWork 라고 하면 두 작업을 연결해서 처리하는 방법은 다음과 같습니다.

각 작업을 WorkRequest 로 만들어서 처음 실행될 compressWork 작업을 WorkManager 의 beginWith() 메서드의 인자로 추가 하고, then() 메서드에 이어할 작업인 uploadWork 를 추가합니다.

이제 WorkManager 는 compressWork 를 적절한 타이밍에 수행하고, compressWork 가 완료 된 이후 uploadWork 를 작업 수행합니다.

이미지를 압축하기 전에 이미지에 필터를 적용하는 작업을 먼저 처리해야 하는 다음과 같은 경우를 생각해봅시다.

이미지가 3장이 존재하고 각 이미지에 필터를 적용합니다. 3장의 이미지가 완료되면 압축 작업을 하고, 업로드 해야 합니다. 이 경우에도 작업을 다음과 같이 연결하여 처리할수 있습니다.

WorkManager 의 beginWith() 메서드에 추가된 세가지의 작업이 완료되는 종료시점이 모두 다르더라도, compressWork 는 세개의 작업이 모두 완료 된 이후에 시작된다는것을 기억해 두세요.

마치며

WorkManager 의 가장 기본이 되는 사용법은 여기까지 입니다. 그리고 위에 서술된 예제는 다음의 GitHub 저장소에서 다운로드 하실 수 있습니다.

아직 WorkManager 의 모든 사용법을 다룬것은 아닙니다.

이미지의 압축 과 업로드 작업 중에 개발자는 압축 작업이 현재 처리되고 있는지, 혹은 대기 상태인지, 실패인지 성공인지 어떻게 알수 있을까요?

또한 압축 작업이 완료되고 그 결과물로 생성된 이미지를 업로드 작업에서 사용하려면 압축된 이미지를 어떻게 업로드 작업자 에게 전달할수 있을까요?

이러한 경우에서의 WorkManager 사용법은 다음 포스트 에서 이어서 알아보도록 하겠습니다.

감사합니다.

참고

--

--