본문 바로가기
🖥 Programming/📱 Android (Kotlin)

[Android][kotlin] Android jetpack WorkManager (작업예약, 백그라운드 )

by MinChan-Youn 2022. 5. 13.

안녕하세요~ 챠니입니다! :)

오늘은 Android Jetpack WorkManager에 대해서 알아보겠습니다!

 

 

Jetpack?, WorkManager? 뭐야?

Jetpack개발자가 관심이 있는 코드에 집중할 수 있도록 권장사항 준수, 상용구 코드 축소, 모든 Android 버전 및 기기에서 일관되게 작동하는 코드 작성을 돕는 라이브러리 모음
WorkManager지속적인 작업에 권장되는 솔루션입니다. 앱이 다시 시작되거나 시스템이 재부팅될 때 작업이 예약된 채로 남아 있으면 그 작업은 유지됩니다. 대부분의 백그라운드 처리는 지속적인 작업을 통해 가장 잘 처리되므로 WorkManager는 백그라운드 처리에 권장하는 기본 API로 볼 수 있습니다.

WorkManager 작업 유형 및 흐름도

 

 

WorkManager 특징

WorkManager는 더 간단하고 일관성 있는 API를 제공할 뿐만 아니라 여러 가지 중요한 이점을 제공합니다.

작업 제약 조건

작업 제약 조건을 사용하여 작업을 실행하는 데 최적인 조건을 선언적으로 정의합니다. 예를 들어, 기기가 무제한 네트워크에 있을 때 또는 기기가 유휴 상태이거나 배터리가 충분할 때만 실행합니다.

강력한 예약 관리

WorkManager를 사용하면 가변 일정 예약 기간을 통해 한 번 또는 반복적으로 실행할 작업을 예약할 수 있습니다. 작업에 태그 및 이름을 지정하여 고유 작업 및 대체 가능한 작업을 예약하고 작업 그룹을 함께 모니터링하거나 취소할 수 있습니다.
예약된 작업은 내부적으로 관리되는 SQLite 데이터베이스에 저장되며 WorkManager에서 기기를 재부팅해도 작업이 유지되고 다시 예약되도록 보장합니다.
또한 WorkManager는 절전 기능을 사용하고 권장사항(예: 잠자기 모드)을 준수하므로 배터리 소모를 걱정하지 않아도 됩니다.

신속 처리 작업

WorkManager를 사용하여 백그라운드에서 즉시 실행할 작업을 예약할 수 있습니다. 사용자에게 중요하고 몇 분 내에 완료되는 작업에는 신속 처리 작업을 사용해야 합니다.

유연한 재시도 정책

경우에 따라 작업이 실패하기도 합니다. WorkManager는 구성 가능한 지수 백오프 정책을 비롯해 유연한 재시도 정책을 제공합니다.

작업 체이닝

복잡한 관련 작업의 경우 직관적인 인터페이스를 사용하여 개별 작업을 함께 체이닝하면 순차적으로 실행할 작업과 동시에 실행할 작업을 제어할 수 있습니다.

*추가적인 Jetpack 설명은 아래링크를 참고해주세요!
https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko

 

WorkManager로 작업 예약  |  Android 개발자  |  Android Developers

WorkManager로 작업 예약  Android Jetpack의 일부 WorkManager는 지속적인 작업에 권장되는 솔루션입니다. 앱이 다시 시작되거나 시스템이 재부팅될 때 작업이 예약된 채로 남아 있으면 그 작업은 유지됩

developer.android.com

 

 

 

WorkManager 장점

안드로이드가 버전이 계속되면서 보안성이 강화되고 기존에 있던 백그라운드 작업진행에 제약이 많이 생기게 되었습니다.

Service, Boardcast Receiver를 통해 프로세스를 깨워 작업을 진행했지만 Android M(API 23)부터 백그라운드 작업에 제약사항들이 생기게 되어 점차 많은 조건을 충족을 시켜야만 했습니다.

하지만 Android jetpack의 목적에 따라 WorkManager를 사용하면 보다 더 편리하게 작업을 진행 할 수 있습니다.

WorkManager를 통해서 앱이 꺼진상태인 백그라운드에서도 쉽게 실행할 수 있는 장점이 있다.

서버에게 데이터 전송 또는 서버 동기화, 이미지 저장 등 작업을 프로세스 종료와 상관없이 작업을 진행할 수 있습니다.

또 프로세스가 종료되었다고해서 WorkManager가 계속해서 프로세스를 잡아먹어 배터리소모를 시키는 것이 아닌 작업이 진행될 때에만 WorkManager가 실행이 되기 때문에 자체적으로 배터리관리를 할 수 있는 장점이 있습니다.

 

 

 

 

WorkManager 어떻게 사용하는거지?

Android jetpack의 목적에 따라 WorkManager를 사용하면 보다 더 편리하게 작업을 진행 할 수 있습니다.

위에도 설명되어있듯이 WorkManager를 통해서 앱이 꺼진상태인 백그라운드에서도 쉽게 실행할 수 있는 장점이 있습니다.

 

우선 WorkManager에 대한 공식문서는 아래와 같습니다.

https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko 

 

WorkManager로 작업 예약  |  Android 개발자  |  Android Developers

WorkManager로 작업 예약  Android Jetpack의 일부 WorkManager는 지속적인 작업에 권장되는 솔루션입니다. 앱이 다시 시작되거나 시스템이 재부팅될 때 작업이 예약된 채로 남아 있으면 그 작업은 유지됩

developer.android.com

 

WorkManager를 어떻게 사용하는 것인지 다들 궁굼할텐데요

다음과 같은 WorkFlow가 있다는 가정을 하고 진행하겠습니다.

work의 순서도에 따라 각 데이터를 전달하여 Log를 출력하는 기능을 가진 앱을 만들어 보겠습니다.

Android WorkManager 흐름도 예시

 

 

1. build.gradle(:app) dependency추가

dependencies {
    val work_version = "2.7.1"

    // (Java only)
    implementation("androidx.work:work-runtime:$work_version")

    // Kotlin + coroutines
    implementation("androidx.work:work-runtime-ktx:$work_version")

    // optional - RxJava2 support
    implementation("androidx.work:work-rxjava2:$work_version")

    // optional - GCMNetworkManager support
    implementation("androidx.work:work-gcm:$work_version")

    // optional - Test helpers
    androidTestImplementation("androidx.work:work-testing:$work_version")

    // optional - Multiprocess support
    implementation "androidx.work:work-multiprocess:$work_version"
}

 

2. MainActivity.kt

//MainActivity.kt
class MainActivity : AppCompatActivity() {
    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initWorkManager()
    }

    private fun initWorkManager() {
        /** WorkManager item
        val workA = OneTimeWorkRequestBuilder<WorkManagerWorker>().setInputData(workDataOf("data" to "A")).build()
        val workB = OneTimeWorkRequestBuilder<WorkManagerWorker>().setInputData(workDataOf("data" to "B")).build()
        val workC = OneTimeWorkRequestBuilder<WorkManagerWorker>().setInputData(workDataOf("data" to "C")).build()
        val workD = OneTimeWorkRequestBuilder<WorkManagerWorker>().setInputData(workDataOf("data" to "D")).build()
        val workE = OneTimeWorkRequestBuilder<WorkManagerWorker>().setInputData(workDataOf("data" to "E")).build()

        /** WorkManager 생성 */
        val chain1 = WorkManager.getInstance(this).beginWith(workA).then(workB)
        val chain2 = WorkManager.getInstance(this).beginWith(workC).then(workD)

        /** WorkManager 실행 (직렬, 병렬) */
        val chainAll = WorkContinuation.combine(listOf(chain1, chain2)).then(workE)
        chainAll.enqueue()
    }
}

 

3. WorkManagerWorker.kt

//WorkManagerWorker.kt
class WorkManagerWorker(appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) {
    override fun doWork(): Result {
        val w_data = inputData.getString("data").toString()
        Log.e("WorkManager", "w_data: $w_data")

        return Result.success()
    }
}

 

WorkManager 실행결과

실행결과는 아래와 같습니다. 이해를 돕기 위해 사진에 노란색 네모를 그려 같은 시간대라고 볼 수 있도록 했습니다.

Log의 시간을 보시면 A,C -> B,D -> D  순서와 같이 Log가 출력된것을 볼 수 있습니다.

이렇게 WorkManager에 직렬, 병렬을 설정하여 자신이 작업하고자하는 Work를 만들어 진행할 수 있는 것을 볼 수 있습니다.

 

 

 


(추가1) WorkManager-Constraint(제약사항) 추가

Work를 생성할때 Constraint 즉 제약사항을 추가하는 방법에 대해서 알아보겠습니다.

제약설정은 아래와 같이 설정할 수 있습니다.

val w_constraint = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)    //네트워크가 연결된 경우
    .setRequiredNetworkType(NetworkType.UNMETERED)    //무제한 네트워크에 연결된 경우(ex. WIFI 등)
    .setRequiredNetworkType(NetworkType.METERED)      //데이터 통신망에 연결된 경우
    .setRequiredNetworkType(NetworkType.NOT_REQUIRED) //네트워크가 필요 없는 경우
    .setRequiredNetworkType(NetworkType.NOT_ROAMING)  //비 로밍 네트워크가 연결된 경우

    .setRequiresBatteryNotLow(true) //기기의 배터리 부족모드인 경우 제업 제한여부 설정
    .setRequiresCharging(true)      //기기가 충전중인 경우에만 작업 실행
    .setRequiresDeviceIdle(true)    //작업이 실행되기전 사용자 기기가 휴혹 상태여야함. 사용자 기기에서 활발하게 실행되는
                                    //다른앱의 성능에 부정적인 영향을 줄 수 있는 배치작업 실행하는데 유용
    .setRequiresStorageNotLow(true) //사용자 기기 저장공이 부족한 경우 작업 제한여부 설정
    .build()

val work_constraint = OneTimeWorkRequestBuilder<WorkManagerWorker>()
    .setConstraints(w_constraint) //제약설정
    .build()

 

작업 제약조건

옵션 설명
NetworkType 작업이 필요한 네트워크 유형을 제한
BatteryNotLow 기기의 배터리 부족모드인경우 작업을 제한여부를 설정
RequiresCharging 기기가 충전중인 경우에만 작업을 실행할 여부를 설정
DeviceIdle 기기가 유휴상태에서만 작업할 여부를 설정
StorageNotLow 기기의 저장공간이 부족한 경우 작업할 여부를 설정

 

NetworkType의 종류

옵션 설명
CONNECTED 네트워크가 연결되어있는 경우
UNMETERED 무제한 네트워크에 연결되어있는경우 ex) Wifi
METERED 데이터 통신망에 연결되어있는 경우
NOT_REQUIRED 네트워크가 필요없는 경우
NOT_ROAMING 비 로밍 네트워크가 연결이되어있는 경우

 

 

(추가2) WorkManager-Delay(딜레이) 추가

Work를 생성할때 Delay를 같이 설정하는 방법에 대해서 알아보겠습니다.

아래 코드예시와 같이 setInitalDealy를 통해서 work의 Delay를 설정할 수 있습니다.

val work_delay = OneTimeWorkRequestBuilder<WorkManagerWorker>()
    .setInitialDelay(10, TimeUnit.MINUTES)
    .build()

Delay TimeUnit은 총 7개로 아래와 같습니다. (나노초, 초, 분, 시간, 일 등등)

NANOSECONDS,
MICROSECONDS,
MILLISECONDS,
SECONDS,
MINUTES,
HOURS,
DAYS;

 

 

 

전체 소스코드

[소스코드]
https://github.com/younminchan/kotlin-jetpack-example/tree/main/WorkManager-kotlin

 

GitHub - younminchan/kotlin-jetpack-example: Android Jetpack Example

Android Jetpack Example. Contribute to younminchan/kotlin-jetpack-example development by creating an account on GitHub.

github.com

 

 

질문 또는 궁굼한 부분은 댓글을 남겨주세요! 친절하게 답변드리겠습니다!

응원의 댓글은 저에게 큰 힘이 된답니다! :)

즐거운 하루되세요!

 

깃허브 보러 놀러오세요 👇 (맞팔환영)

https://github.com/younminchan

 

younminchan - Overview

안드로이드 2년차 개발자 •⚽️/🎤/🥁/🖥/🏃‍♂️/🚴‍♂️/🤟 TechBlog⬇️ minchanyoun.tistory.com - younminchan

github.com