Android

WorkManager (1) : 작업 설정/예약하기

까망사과 2022. 12. 2. 02:00

WorkManager는 지속적으로 작업을 실행하기 위해 사용하는 API다. 앱 및 시스템을 재시작해도 작업을 유지할 수 있으므로 JobScheduler를 대체할 수 있다. 일반적으로 백그라운드에서 실행하는 작업을 지속해야 하기 때문에 백그라운드 작업을 실행할 때 사용하기를 권장하는 API다.

 

WorkManager가 관리하는 작업의 유형은 다음과 같다.

  • 즉시 실행
  • 장시간 실행
  • 지연 가능

 

Worker로 작업 단위 정의하기

Worker 추상 클래스의 하위 클래스를 정의하여 작업 단위를 정의한다. 실행하고자 하는 작업의 로직은 doWork()를 재정의하여 구현한다. doWork()ListenableWorker.Result 인스턴스를 반환하는데 이는 작업의 성공 여부를 나타내며 다음 3가지 경우로 나뉜다.

  • Result.success()
    작업 성공
  • Result.failure()
    작업 실패
  • Result.retry()
    작업 실패 + 설정된 재시도 정책에 따라 나중에 재시도
class UploadWorker(
    appContext: Context,
    workerParams: WorkerParameters) : Worker(appContext, workerParams) {
    override fun doWork(): Result {
        // 작업 로직
        uploadImages()

        // 작업 성공 여부 반환
        return Result.success()
    }
}

 

WorkRequest 생성하기

WorkRequestWorkManager에 예약할 작업에 대한 정보를 포함하는 클래스다. Builder 클래스를 사용하여 인스턴스를 생성하며 다음 사항들을 설정할 수 있다.

  • 작업 태그 및 ID
  • 중요한 작업인지 여부
  • 초기 지연 시간
  • 제약 조건
  • 백오프 정책 및 지연 시간
  • 작업 결과 유지 시간
  • 작업을 실행하는 데 필요한 데이터

 

WorkRequest는 추상 클래스이다. 작업 유형에 따라 하위 클래스인 OneTimeWorkRequest 또는 PeriodicWorkRequest를 사용한다.

 

일회성 작업

한 번만 실행할 작업에 대한 WorkRequestOneTimeWorkRequest를 사용한다. OneTimeWorkRequest.Builder 객체를 생성하는 방법은 2가지로 나뉜다.

 

추가 설정이 필요 없을 정도로 작업이 간단한 경우 OneTimeWorkRequest.from(Class<out ListenableWorker>)를 사용한다.

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

 

복잡한 경우 Builder 클래스를 사용한다. Kotlin을 사용하는 경우 OneTimeWorkRequestBuilder 메서드를 사용할 수 있다.

val uploadWorkRequest: WorkRequest =
    OneTimeWorkRequestBuilder<MyWork>()
        // 추가 설정
        .build()

 

주기적으로 실행되는 작업

주기적으로 실행할 작업에 대한 WorkRequestPeriodicWorkRequest를 사용한다. PeriodicWorkRequest 객체는 Builder 클래스를 사용하여 생성한다. Kotlin을 사용하는 경우 PeriodicWorkRequestBuilder 메서드를 사용할 수 있다. 파라미터는 작업 실행 주기에 대한 정보를 나타낸다.

val saveRequest =
    PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
        // 추가 설정
        .build()

 

가변 실행 간격

작업을 각 실행 주기 내의 가변 주기(flex period) 내에 실행하도록 할 수 있다.

각 실행 주기의 끝에 작업을 실행할 수 있는 가변 주기가 포함되어 있다.

 

작업 실행 주기 및 가변 주기를 설정하려면 PeriodicWorkRequest.Builder 객체를 생성할 때 이에 대한 정보를 파라미터로 전달해야 한다. 다음은 작업 실행 주기가 1시간이고 그 중 가변 주기가 마지막 15분인 주기 작업 예시다.

val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
       1, TimeUnit.HOURS,    // 작업 실행 주기와 시간 단위
       15, TimeUnit.MINUTES) // 가변 주기와 시간 단위
    .build()

 

작업 제약 조건

작업을 실행하기 위해 충족시켜야 하는 제약 조건을 설정할 수 있다. WorkManager에서 사용할 수 있는 제약 조건은 다음과 같다.

  • NetworkType
    작업 실행 시 필요한 네트워크 유형을 제한한다.
  • BatteryNotLow
    true로 설정하면 배터리 부족 상태에서 작업이 실행되지 않는다.
  • RequiresCharging
    true로 설정하면 충전 중이어야 작업이 실행된다.
  • DeviceIdle
    true로 설정하면 디바이스가 유휴 상태이어야 작업이 실행된다.
  • StorageNotLow
    true로 설정하면 저장공간이 부족하지 않아야 작업이 실행된다.

 

제약 조건은 Constraints.Builder 클래스를 통해 생성된 Constraints 객체에 포함된다. 이 Constraints 객체를 WorkRequest.Builder#setConstraints(Constraints)에 전달하면 작업에 제약 조건이 설정된다. 다음은 충전 중이고 Wi-Fi가 연결되어 있어야 실행되는 작업 예시다.

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED)
    .setRequiresCharging(true)
    .build()

val myWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<MyWork>()
    .setConstraints(constraints)
    .build()

 

제약 조건이 설정된 작업은 조건을 모두 충족해야 실행된다. 작업을 이미 실행 중인 도중에 조건을 충족하지 못하게 되는 경우 작업이 중단된다. 그러고 나서 조건을 모두 충족하게 될 때 작업을 재시도한다.

 

작업 딜레이

작업을 WorkManager에 예약할 때 제약 조건이 없거나 모두 충족하는 경우 시스템이 작업을 즉시 실행할 수 있다. 하지만 즉시 실행하지 않고자 한다면 초기에 작업이 지연되는 시간을 설정할 수 있다. WorkRequest.Builder#setInitialDelay(Long, TimeUnit)에 지연 시간 및 시간 단위를 전달한다. 다음은 10분 지연된 뒤 실행되는 일회성 작업 예시다.

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
    .setInitialDelay(10, TimeUnit.MINUTES)
    .build()

 

재시도 및 백오프 정책

작업을 재시도해야 하는 경우 Worker#doWork()에서 Result.retry()를 반환한다. 그러고 나서 백오프 딜레이 및 정책에 따라 작업을 재시도한다.

  • 백오프 딜레이
    작업을 처음으로 재시도하기 전 대기해야 하는 시간을 나타낸다. 
  • 백오프 정책
    작업 재시도 횟수가 증가함에 따라 백오프 딜레이가 증가하는 방식을 나타낸다. BackoffPolicy.LINEARBackoffPolicy.EXPONENTIAL을 사용할 수 있다.

기본 백오프 딜레이는 10초이며 기본 백오프 정책은 EXPONENTIAL이지만 WorkRequest.Builder#setBackoffCriteria(BackoffPolicy, Long, TimeUnit) 를 사용하여 재정의할 수 있다.

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
    .setBackoffCriteria(
        // 백오프 정책: 선형
        BackoffPolicy.LINEAR,
        // 백오프 딜레이: 10초 (단위 고려 필요)
        OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
        // 시간 단위: ms
        TimeUnit.MILLISECONDS) 
    .build()

 

작업 ID 및 태그

모든 WorkRequest에는 ID가 있기 때문에 작업 취소 및 진행 상황 모니터링을 하는 데 사용할 수 있다. WorkRequest의 ID는 WorkRequest.Builder#setId(UUID)를 사용하여 설정하고 WorkRequest.id 프로퍼티로 확인할 수 있다.

 

서로 관련된 작업 항목에 태그를 추가할 수 있다. 같은 태그를 설정한 작업 항목을 함께 실행하거나 취소할 수 있다. 작업 항목에 태그를 추가하려면 WorkRequest.Builder#addTag(String)을 사용하면 된다.

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
    .addTag("cleanup")
    .build()

 

입력 데이터

작업을 실행할 때 입력 데이터가 필요한 경우가 있다. 입력 데이터는 Data 객체를 사용한다.

 

Data는 내부의 Map<String, Object>에 데이터를 저장한다. Data 객체는 Data.Builder 클래스를 사용하여 생성한다. workDataOf(vararg Pair<String, Any?>) 함수로도 생성할 수 있다.

val myUploadWorkRequest = OneTimeWorkRequestBuilder<UploadWork>()
    .setInputData(
        workDataOf("IMAGE_URI" to "http://..."))
    .build()

 

작업 로직에서 Worker#getInputData()를 호출하여 입력 데이터에 액세스할 수 있다.

class UploadWork(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {

    override fun doWork(): Result {
        val imageUriInput =
            inputData.getString("IMAGE_URI") ?: return Result.failure()

        uploadFile(imageUriInput)
        return Result.success()
    }
    ...
}

'Android' 카테고리의 다른 글

WorkManager (3) : 작업 관리하기  (0) 2022.12.05
WorkManager (2) : 작업 상태  (0) 2022.12.02
DataStore  (0) 2022.11.30
Lifecycle  (0) 2022.11.11
데이터 바인딩 (4) : 양방향 바인딩  (0) 2022.11.05