이 Codelab은 Android Kotlin 기초 교육 과정의 일부입니다. Codelab을 순서대로 진행한다면 이 과정을 통해 최대한의 가치를 얻을 수 있을 것입니다. 모든 과정 Codelab은 Android Kotlin 기초 Codelab 방문 페이지에 나열되어 있습니다.
소개
대부분의 실제 앱은 장기 실행 백그라운드 작업을 실행해야 합니다. 예를 들어 앱이 서버에 파일을 업로드하거나 서버에서 데이터를 동기화하여 Room
데이터베이스에 저장하거나 서버에 로그를 전송하거나 데이터에 대해 비용이 많이 드는 작업을 실행할 수 있습니다. 이러한 작업은 UI 스레드 (기본 스레드)에서 백그라운드로 실행해야 합니다. 백그라운드 작업은 기기의 RAM, 배터리 등 제한된 리소스를 소비합니다. 따라서 백그라운드 작업이 제대로 처리되지 않으면 사용자의 경험이 저하될 수 있습니다.
이 Codelab에서는 WorkManager
를 사용하여 최적화 및 효율적인 방식으로 백그라운드 작업을 예약하는 방법을 알아봅니다. Android에서 백그라운드 처리를 위해 제공되는 다른 솔루션을 자세히 알아보려면 백그라운드 처리 가이드를 참조하세요.
기본 요건
ViewModel
,LiveData
,Room
Android 아키텍처 구성요소 사용 방법LiveData
클래스에서 변환을 실행하는 방법- 코루틴을 빌드하고 실행하는 방법
- 데이터 결합에 결합 어댑터를 사용하는 방법
- 저장소 패턴을 사용하여 캐시된 데이터를 로드하는 방법
학습할 내용
- 작업 단위를 나타내는
Worker
을 만드는 방법 - 수행할 작업을 요청하기 위해
WorkRequest
을 만드는 방법 WorkRequest
에 제약 조건을 추가하여 작업자가 실행되는 방식과 시기를 정의하는 방법WorkManager
를 사용하여 백그라운드 작업을 예약하는 방법
실습할 내용
- 백그라운드 작업을 실행하여 작업자를 만들어 네트워크에서 DevBytes 동영상 재생목록을 미리 가져옵니다.
- 작업자가 주기적으로 실행되도록 예약합니다.
WorkRequest
에 제약 조건을 추가합니다.- 하루에 한 번 실행되는 주기적인
WorkRequest
를 예약합니다.
이 Codelab에서는 이전 Codelab에서 개발한 DevBytes 앱에서 작업합니다. (이 앱이 없는 경우 이 강의의 시작 코드를 다운로드하면 됩니다.)
DevBytes 앱은 Google Android 개발자 관계팀에서 만든 짧은 튜토리얼인 DevByte 동영상 목록을 표시합니다. 동영상에서는 Android 개발을 위한 개발자 기능 및 권장사항을 소개합니다.
하루에 한 번 동영상을 미리 가져와서 앱의 사용자 환경을 향상합니다. 이렇게 하면 사용자가 앱을 여는 즉시 최신 콘텐츠를 받을 수 있습니다.
이 작업에서는 시작 코드를 다운로드하고 검사합니다.
1단계: 시작 앱 다운로드 및 실행하기
이전 Codelab에서 빌드한 DevBytes 앱을 통해 계속 작업할 수 있습니다 (있는 경우). 또는 시작 앱을 다운로드할 수 있습니다.
이 작업에서는 시작 앱을 다운로드하고 실행하여 시작 코드를 확인합니다.
- DevBytes 앱이 없는 경우 GitHub의 DevBytesRepository 프로젝트에서 이 Codelab의 DevBytes 스타터 코드를 다운로드합니다.
- 코드의 압축을 푼 후 Android 스튜디오에서 프로젝트를 엽니다.
- 테스트 기기 또는 에뮬레이터가 아직 연결되지 않은 경우 인터넷에 연결합니다. 앱을 빌드하고 실행합니다. 앱이 네트워크에서 DevByte 동영상 목록을 가져와서 표시합니다.
- 앱에서 동영상을 탭하여 YouTube 앱에서 엽니다.
2단계: 코드 살펴보기
시작 앱에는 이전 Codelab에서 도입된 많은 코드가 제공됩니다. 이 Codelab의 시작 코드에는 네트워킹, 사용자 인터페이스, 오프라인 캐시, 저장소 모듈이 있습니다. WorkManager
를 사용하여 백그라운드 작업을 예약하는 데 집중할 수 있습니다.
- Android 스튜디오에서 모든 패키지를 펼칩니다.
database
패키지를 살펴보세요. 패키지에는 데이터베이스 항목과Room
를 사용하여 구현된 로컬 데이터베이스가 포함되어 있습니다.repository
패키지를 살펴보세요. 패키지에는 앱의 나머지 부분에서 데이터 영역을 추출하는VideosRepository
클래스가 포함되어 있습니다.- 나머지 시작 코드를 직접 살펴보고 이전 Codelab을 사용하여 살펴보세요.
WorkManager
는 Android 아키텍처 구성요소 중 하나이며 Android Jetpack의 일부입니다. WorkManager
는 지연 가능하고 보장된 실행이 필요한 백그라운드 작업에 사용됩니다.
- 지연 가능은 작업을 즉시 실행할 필요가 없음을 의미합니다. 예를 들어 분석 데이터를 서버로 전송하거나 백그라운드에서 데이터베이스를 동기화하는 작업을 지연할 수 있습니다.
- 보장 실행은 앱이 종료되거나 기기가 다시 시작되더라도 작업이 실행됨을 의미합니다.
WorkManager
는 백그라운드 작업을 실행하지만 배터리 문제 및 시스템 상태와 관련된 호환성 문제 및 권장사항을 처리합니다. WorkManager
은 API 수준 14와의 호환성을 제공합니다. WorkManager
는 기기 API 수준에 따라 백그라운드 작업을 예약할 적절한 방법을 선택합니다. API 23 이상에서 JobScheduler
를 사용하거나 AlarmManager
및 BroadcastReceiver
조합을 사용할 수 있습니다.
또한 WorkManager
를 사용하면 백그라운드 작업이 실행되는 기준을 설정할 수 있습니다. 예를 들어 배터리 상태, 네트워크 상태 또는 충전 상태가 특정 기준을 충족하는 경우에만 작업을 실행할 수 있습니다. 이 Codelab의 뒷부분에서 제약 조건을 설정하는 방법을 알아봅니다.
이 Codelab에서는 하루에 한 번 네트워크에서 DevBytes 동영상 재생목록을 미리 가져오는 작업을 예약합니다. 이 작업을 예약하려면 WorkManager
라이브러리를 사용합니다.
build.gradle (Module:app)
파일을 열고WorkManager
종속 항목을 프로젝트에 추가합니다.
최신 버전의 라이브러리를 사용하는 경우 솔루션 앱이 예상대로 컴파일됩니다. 문제가 해결되지 않으면 문제를 해결하거나 아래에 표시된 라이브러리 버전으로 되돌리세요.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
- 프로젝트를 동기화하고 컴파일 오류가 없는지 확인합니다.
프로젝트에 코드를 추가하기 전에 WorkManager
라이브러리의 다음 클래스를 숙지하세요.
Worker
이 클래스에서는 백그라운드에서 실행할 실제 작업 (작업)을 정의합니다. 이 클래스를 확장하고doWork()
메서드를 재정의합니다.doWork()
메서드는 서버와 데이터를 동기화하거나 이미지를 처리하는 등 백그라운드에서 실행할 코드를 배치합니다. 이 작업에서는Worker
를 구현합니다.WorkRequest
이 클래스는 백그라운드에서 작업자를 실행하라는 요청을 나타냅니다.WorkRequest
를 사용하면 연결된 기기 또는 Wi-Fi와 같은Constraints
를 통해 작업자 작업의 실행 시기와 시기를 구성할 수 있습니다. 이후 작업에서WorkRequest
를 구현합니다.WorkManager
이 클래스는WorkRequest
를 예약하고 실행합니다.WorkManager
는 개발자가 지정한 제약조건을 준수하면서 시스템 리소스 부하를 분산하는 방식으로 작업 요청을 예약합니다. 이후 작업에서WorkManager
를 구현합니다.
1단계: 작업자 만들기
이 작업에서는 Worker
을 추가하여 백그라운드에서 DevBytes 동영상 재생목록을 미리 가져옵니다.
devbyteviewer
패키지에서work
이라는 새 패키지를 만듭니다.work
패키지에서RefreshDataWorker
이라는 새 Kotlin 클래스를 만듭니다.CoroutineWorker
클래스에서RefreshDataWorker
클래스를 확장합니다.context
및WorkerParameters
을 생성자 매개변수로 전달합니다.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
}
- 추상 클래스 오류를 해결하려면
RefreshDataWorker
클래스 내에서doWork()
메서드를 재정의합니다.
override suspend fun doWork(): Result {
return Result.success()
}
정지 함수는 나중에 일시중지했다가 다시 시작할 수 있는 함수입니다. 정지 함수는 장기 실행 작업을 실행하고 기본 스레드를 차단하지 않고 완료될 때까지 기다릴 수 있습니다.
2단계: doWork() 구현
Worker
클래스 내의 doWork()
메서드는 백그라운드 스레드에서 호출됩니다. 이 메서드는 동기식으로 작업을 실행하며, ListenableWorker.Result
객체를 반환해야 합니다. Android 시스템은 Worker
를 실행하고 실행을 완료하는 데 최대 10분을 허용하고 ListenableWorker.Result
객체를 반환합니다. 이 기간이 만료되면 시스템에서 Worker
를 강제로 중지합니다.
ListenableWorker.Result
객체를 만들려면 다음 정적 메서드 중 하나를 호출하여 백그라운드 작업의 완료 상태를 나타냅니다.
Result.success()
: 작업이 완료되었습니다.Result.failure()
: 영구적인 실패와 함께 작업이 완료되었습니다.Result.retry()
: 일시적인 오류가 발생했으므로 다시 시도해야 합니다.
이 작업에서는 doWork()
메서드를 구현하여 네트워크에서 DevBytes 동영상 재생목록을 가져옵니다. VideosRepository
클래스의 기존 메서드를 재사용하여 네트워크에서 데이터를 검색할 수 있습니다.
RefreshDataWorker
클래스의doWork()
내에서VideosDatabase
객체 및VideosRepository
객체를 만들고 인스턴스화합니다.
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
return Result.success()
}
RefreshDataWorker
클래스의doWork()
내return
문 위에서try
블록 내에refreshVideos()
메서드를 호출합니다. 작업자가 실행되는 시점을 추적하는 로그를 추가합니다.
try {
repository.refreshVideos( )
Timber.d("Work request for sync is run")
} catch (e: HttpException) {
return Result.retry()
}
"미확인 참조" 오류를 해결하려면 retrofit2.HttpException
를 가져옵니다.
- 다음과 같이 완성된
RefreshDataWorker
클래스를 참고하세요.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
try {
repository.refreshVideos()
} catch (e: HttpException) {
return Result.retry()
}
return Result.success()
}
}
Worker
는 작업 단위를 정의하고 WorkRequest
는 작업 실행 방식과 시기를 정의합니다. WorkRequest
클래스에는 두 가지 구체적인 구현이 있습니다.
OneTimeWorkRequest
클래스는 일회성 작업에 사용됩니다. 일회성 작업은 한 번만 발생합니다.PeriodicWorkRequest
클래스는 간격을 두고 반복되는 작업인 주기적 작업에 사용됩니다.
작업은 일회성이거나 주기적일 수 있으므로 그에 따라 클래스를 선택합니다. 반복 작업 예약에 대한 자세한 내용은 반복 작업 문서를 참고하세요.
이 작업에서는 이전 작업에서 만든 작업자를 실행하도록 WorkRequest
을 정의하고 예약합니다.
1단계: 반복 작업 설정하기
Android 앱 내의 Application
클래스는 활동 및 서비스와 같은 다른 모든 구성요소를 포함하는 기본 클래스입니다. 애플리케이션이나 패키지의 프로세스가 생성되면 Application
클래스 (또는 Application
의 서브클래스)가 다른 클래스보다 먼저 인스턴스화됩니다.
이 샘플 앱에서 DevByteApplication
클래스는 Application
클래스의 서브클래스입니다. DevByteApplication
클래스는 WorkManager
를 예약하는 데 적합한 장소입니다.
DevByteApplication
클래스에서 반복 백그라운드 작업을 설정하는setupRecurringWork()
메서드를 만듭니다.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
setupRecurringWork()
메서드 내에서PeriodicWorkRequestBuilder()
메서드를 사용하여 하루에 한 번 실행되도록 주기적 작업 요청을 만들고 초기화합니다. 이전 작업에서 만든RefreshDataWorker
클래스를 전달합니다.TimeUnit.
DAYS
의 시간 단위를 사용하여1
의 반복 간격으로 전달합니다.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.build()
오류를 해결하려면 java.util.concurrent.TimeUnit
를 가져옵니다.
2단계: WorkManager로 WorkRequest 예약
WorkRequest
를 정의한 후에는 enqueueUniquePeriodicWork()
메서드를 사용하여 WorkManager
로 예약할 수 있습니다. 이 메서드를 사용하면 대기열에 고유한 PeriodicWorkRequest
라는 이름을 추가할 수 있습니다. 이때 특정 이름의 PeriodicWorkRequest
은 한 번에 하나만 활성화할 수 있습니다.
예를 들어 하나의 동기화 작업만 활성화되도록 설정할 수 있습니다. 하나의 동기화 작업이 대기 중인 경우 기존PeriodicWorkPolicy를 사용해 실행하거나 새 작업으로 교체할 수 있습니다.
WorkRequest
를 예약하는 방법에 관한 자세한 내용은 WorkManager
문서를 참고하세요.
RefreshDataWorker
클래스의 클래스 시작 화면에 컴패니언 객체를 추가합니다. 이 작업자를 고유하게 식별할 작업 이름을 정의합니다.
companion object {
const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
DevByteApplication
클래스의setupRecurringWork()
메서드 끝에서enqueueUniquePeriodicWork()
메서드를 사용하여 작업을 예약합니다. ExistingPeriodicWorkPolicy의KEEP
enum을 전달합니다.repeatingRequest
을PeriodicWorkRequest
매개변수로 전달합니다.
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
동일한 이름의 대기 중인 (미완료) 작업이 있는 경우 ExistingPeriodicWorkPolicy.
KEEP
매개변수는 WorkManager
가 이전 주기 작업을 유지하고 새 작업 요청을 삭제합니다.
DevByteApplication
클래스 시작 부분에CoroutineScope
객체를 만듭니다.Dispatchers.Default
을 생성자 매개변수로 전달합니다.
private val applicationScope = CoroutineScope(Dispatchers.Default)
DevByteApplication
클래스에서 코루틴을 시작하기 위해delayedInit()
라는 새 메서드를 추가합니다.
private fun delayedInit() {
applicationScope.launch {
}
}
delayedInit()
메서드 내에서setupRecurringWork()
를 호출합니다.- Timber 초기화를
onCreate()
메서드에서delayedInit()
메서드로 이동합니다.
private fun delayedInit() {
applicationScope.launch {
Timber.plant(Timber.DebugTree())
setupRecurringWork()
}
}
DevByteApplication
클래스의onCreate()
메서드 끝부분에delayedInit()
메서드 호출을 추가합니다.
override fun onCreate() {
super.onCreate()
delayedInit()
}
- Android 스튜디오 창 하단에서 Logcat 창을 엽니다.
RefreshDataWorker
의 필터를 사용합니다. - 앱을 실행합니다.
WorkManager
는 반복 작업을 즉시 예약합니다.
Logcat 창에서 작업 요청이 예약되었음을 확인한 다음 성공적으로 실행되었음을 보여주는 로그 구문을 확인합니다.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
WM-WorkerWrapper
로그는 WorkManager
라이브러리에서 표시되므로 이 로그 메시지를 변경할 수 없습니다.
3단계: (선택사항) 최소 간격으로 WorkRequest 예약하기
이 단계에서는 시간 간격을 1일에서 15분으로 줄입니다. 이렇게 하면 작업 중인 정기 작업 요청의 로그를 확인할 수 있습니다.
DevByteApplication
클래스의setupRecurringWork()
메서드 내에서 현재repeatingRequest
정의를 주석 처리합니다.15
분의 주기적인 반복 간격으로 새 작업 요청을 추가합니다.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
// .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.build()
- Android 스튜디오에서 Logcat 창을 열고
RefreshDataWorker
로 필터링합니다. 이전 로그를 지우려면 Clear logcat 아이콘을 클릭합니다..
- 앱을 실행하면
WorkManager
에서 반복 작업을 즉시 예약합니다. Logcat 창에서 로그를 확인합니다. 작업 요청은 15분마다 실행됩니다. 15분 후에 다른 작업 요청 로그 세트가 표시되는지 확인합니다. 앱을 실행 상태로 두거나 닫아도 됩니다. 그러면 직장 관리자가 계속 실행됩니다.
간격이 15분 미만이거나 15분을 넘기는 경우가 있습니다. 정확한 시기는 OS 배터리 최적화에 따라 달라집니다.
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
수고하셨습니다. 작업자를 만들고 WorkManager
로 작업 요청을 예약했습니다. 그러나 문제가 있습니다. 제약 조건을 지정하지 않았습니다. WorkManager
는 기기의 배터리가 부족하거나 절전 모드에 있거나 네트워크에 연결되어 있지 않더라도 하루에 한 번 작업을 예약합니다. 이는 기기의 배터리와 성능에 영향을 미치며 사용자 환경을 저해할 수 있습니다.
다음 작업에서는 제약조건을 추가하여 이 문제를 해결합니다.
이전 작업에서는 WorkManager
를 사용하여 작업 요청을 예약했습니다. 이 작업에서는 작업을 실행할 기준을 추가합니다.
WorkRequest
를 정의할 때 Worker
를 실행할 시점에 관한 제약 조건을 지정할 수 있습니다. 예를 들어, 기기가 유휴 상태일 때만 또는 기기가 전원에 연결되어 있고 Wi-Fi에 연결되어 있을 때만 작업을 실행하도록 지정할 수 있습니다. 작업을 재시도하기 위한 백오프 정책을 지정할 수도 있습니다. 지원되는 제약 조건은 Constraints.Builder
에 설정된 메서드입니다. 자세한 내용은 작업 요청 정의를 참고하세요.
1단계: 제약 조건 객체 추가 및 제약 조건 1개 설정
이 단계에서는 Constraints
객체를 만들고 객체에 유형 제약 조건인 네트워크 유형 제약조건을 설정합니다. {0}제약 조건이 하나뿐인 로그를 쉽게 확인할 수 있습니다. 이후 단계에서 다른 제약 조건을 추가합니다.)
DevByteApplication
클래스의setupRecurringWork()
시작 부분에서Constraints
유형의val
을 정의합니다.Constraints.Builder()
메서드를 사용합니다.
val constraints = Constraints.Builder()
오류를 해결하려면 androidx.work.Constraints
를 가져옵니다.
setRequiredNetworkType()
메서드를 사용하여constraints
유형에 네트워크 유형 제약조건을 추가합니다.UNMETERED
enum을 사용하면 기기가 무제한 네트워크에 있을 때만 작업 요청이 실행됩니다.
.setRequiredNetworkType(NetworkType.UNMETERED)
build()
메서드를 사용하여 빌더에서 제약 조건을 생성합니다.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
이제 새로 만든 Constraints
객체를 작업 요청으로 설정해야 합니다.
DevByteApplication
클래스의setupRecurringWork()
메서드 내에서Constraints
객체를 주기적 작업 요청인repeatingRequest
로 설정합니다. 제약 조건을 설정하려면build()
메서드 호출 위에setConstraints()
메서드를 추가합니다.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.setConstraints(constraints)
.build()
2단계: 앱 실행 및 로그 확인
이 단계에서는 앱을 실행하고 제한된 작업 요청이 백그라운드에서 정기적으로 실행되는 것을 확인합니다.
- 기기나 에뮬레이터에서 앱을 제거하여 이전에 예약된 작업을 취소합니다.
- Android 스튜디오에서 Logcat 창을 엽니다. Logcat 창에서 왼쪽의 Clear logcat 아이콘
을 클릭하여 이전 로그를 삭제합니다.
work
의 필터를 사용합니다. - 기기 또는 에뮬레이터에서 Wi-Fi를 사용 중지하여 제약 조건이 어떻게 작동하는지 확인합니다. 현재 코드는 제약 조건을 하나만 설정하여 요청이 무제한 네트워크에서만 실행되어야 함을 나타냅니다. Wi-Fi가 꺼져 있기 때문에 기기가 데이터 전송량 제한이 있는 네트워크나 데이터 전송량 제한이 없는 네트워크에 연결되어 있지 않습니다. 따라서 이 제약조건은 충족되지 않습니다.
- 앱을 실행하고 Logcat 창을 확인합니다.
WorkManager
는 백그라운드 작업을 즉시 예약합니다. 네트워크 제약조건을 충족하지 않으므로 작업이 실행되지 않습니다.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- 기기 또는 에뮬레이터에서 Wi-Fi를 사용 설정하고 Logcat 창을 확인합니다. 이제 네트워크 제약 조건이 충족된다면 예약된 백그라운드 작업이 약 15분마다 실행됩니다.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
3단계: 제약 조건 추가
이 단계에서는 PeriodicWorkRequest
에 다음 제약 조건을 추가합니다.
- 배터리 잔량이 부족합니다.
- 기기 충전 중입니다.
- 기기 유휴 상태. API 수준 23 (Android M) 이상에서만 사용 가능
DevByteApplication
클래스에서 다음을 구현합니다.
DevByteApplication
클래스의setupRecurringWork()
메서드 내에서 배터리가 부족하지 않은 경우에만 작업 요청이 실행되어야 함을 나타냅니다.build()
메서드 호출 전에 제약 조건을 추가하고setRequiresBatteryNotLow()
메서드를 사용합니다.
.setRequiresBatteryNotLow(true)
- 기기가 충전 중일 때만 실행되도록 작업 요청을 업데이트합니다.
build()
메서드 호출 전에 제약 조건을 추가하고setRequiresCharging()
메서드를 사용합니다.
.setRequiresCharging(true)
- 기기가 유휴 상태일 때만 실행되도록 작업 요청을 업데이트합니다.
build()
메서드 호출 전에 제약조건을 추가하고setRequiresDeviceIdle()
메서드를 사용합니다. 이 제약조건은 사용자가 기기를 활발하게 사용하지 않을 때만 작업 요청을 실행합니다. 이 기능은 Android 6.0 (Marshmallow) 이상에서만 사용할 수 있으므로 SDK 버전M
이상을 위한 조건을 추가하세요.
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
다음은 constraints
객체의 전체 정의입니다.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
setupRecurringWork()
메서드 내에서 요청 간격을 다시 하루에 한 번 변경합니다.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
다음은 주기적 작업 요청이 예약된 시간을 추적할 수 있도록 로그와 함께 setupRecurringWork()
메서드의 전체 구현입니다.
private fun setupRecurringWork() {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Timber.d("Periodic Work request for sync is scheduled")
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
}
- 이전에 예약된 작업 요청을 삭제하려면 기기나 에뮬레이터에서 DevBytes 앱을 제거하세요.
- 앱을 실행하면
WorkManager
가 즉시 작업 요청을 예약합니다. 작업 요청은 모든 제약조건이 충족되는 경우 하루에 한 번 실행됩니다. - 이 작업 요청은 앱이 실행되고 있지 않더라도 앱이 설치되어 있는 동안 백그라운드에서 실행됩니다. 따라서 휴대전화에서 앱을 제거해야 합니다.
정답입니다. DevBytes 앱에서 매일 프리패치하는 배터리 절약 작업 요청을 구현하고 예약했습니다. WorkManager
에서 작업을 예약하고 실행하여 시스템 리소스를 최적화합니다. 사용자와 배터리에 매우 만족할 것입니다.
Android 스튜디오 프로젝트: DevBytesWorkManager.
WorkManager
API를 사용하면 안정적으로 실행해야 하는 지연 가능한 비동기 작업을 쉽게 예약할 수 있습니다.- 대부분의 실제 앱은 장기 실행 백그라운드 작업을 실행해야 합니다. 최적화되고 효율적인 방식으로 백그라운드 작업을 예약하려면
WorkManager
를 사용합니다. WorkManager
라이브러리의 기본 클래스는Worker
,WorkRequest
,WorkManager
입니다.Worker
클래스는 작업 단위를 나타냅니다. 백그라운드 작업을 구현하려면Worker
클래스를 확장하고doWork()
메서드를 재정의합니다.WorkRequest
클래스는 작업 단위의 실행 요청을 나타냅니다.WorkRequest
는WorkManager
에서 예약하는 작업의 매개변수를 지정하는 기본 클래스입니다.WorkRequest
클래스의 두 가지 구체적인 구현이 있습니다. 일회성 작업의 경우OneTimeWorkRequest
이고, 정기 작업 요청의 경우PeriodicWorkRequest
입니다.WorkRequest
를 정의할 때Constraints
를 지정하여Worker
를 실행할 시점을 지정할 수 있습니다. 제약조건에는 기기 연결 여부, 기기 유휴 상태, Wi-Fi 연결 여부 등이 포함됩니다.WorkRequest
에 제약 조건을 추가하려면Constraints.Builder
문서에 나열된 집합 메서드를 사용합니다. 예를 들어 기기 배터리 잔량이 부족한 경우WorkRequest
을 실행하면 안 된다고 표시하려면setRequiresBatteryNotLow()
set 메서드를 사용합니다.WorkRequest
를 정의한 후에 Android 시스템에 작업을 전달합니다. 이렇게 하려면WorkManager
enqueue
메서드 중 하나를 사용하여 작업을 예약합니다.Worker
이 실행되는 정확한 시간은WorkRequest
에 사용된 제약조건과 시스템 최적화에 따라 다릅니다.WorkManager
는 이러한 제한사항을 고려하여 최상의 동작을 제공하도록 설계되었습니다.
Udacity 과정:
Android 개발자 문서:
기타:
이 섹션에는 강사가 진행하는 과정의 일부로 이 Codelab을 통해 작업하는 학생들의 숙제 과제가 나와 있습니다. 강사는 다음을 처리합니다.
- 필요한 경우 과제를 할당합니다.
- 학생에게 과제 과제를 제출하는 방법을 알려주세요.
- 과제 과제를 채점합니다.
강사는 이러한 추천을 원하는 만큼 사용할 수 있으며 다른 적절한 숙제를 할당해도 좋습니다.
이 Codelab을 직접 학습하고 있다면 언제든지 숙제를 통해 지식을 확인해 보세요.
질문 1
WorkRequest
클래스의 구체적인 구현은 무엇인가요?
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest
및 PeriodicWorkRequest
▢ OneTimeWorkRequest
및 RecurringWorkRequest
▢ OneTimeOffWorkRequest
및 RecurringWorkRequest
질문 2
다음 중 WorkManager
가 API 23 이상에서 백그라운드 작업을 예약하는 데 사용하는 클래스는 무엇인가요?
MRAID만 JobScheduler
▢ BroadcastReceiver
및 AlarmManager
▢ AlarmManager
및 JobScheduler
▢ Scheduler
및 BroadcastReceiver
질문 3
WorkRequest
에 제약 조건을 추가하는 데 사용하는 API는 무엇인가요?
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
다음 강의인
이 과정의 다른 Codelab 링크는 Android Kotlin 기초 Codelab 방문 페이지를 참고하세요.