WorkManager는 안드로이드의 백그라운드 작업을 관리하기 위한 시스템으로 안드로이드 제트팩에서 나왔다. 백그라운드 작업을 스케쥴링 할 수 있고, 앱의 종료에도 이 작업의 실행 유지를 보장해준다고 한다.
https://proandroiddev.com/experiments-with-android-workmanager-our-new-reliable-assistant-for-deferrable-background-work-9baeb6bd7db3
Create a Worker class -> create work request -> enque the request -> get status updates의 4단계로 스케쥴링이 이루어진다.
참고 최소 API 레벨은 26이 되어야 한다.
https://developer.android.com/topic/libraries/architecture/workmanager/basics
work manager dependency 세팅을 가져온다.
def work_version = "2.7.1"
implementation "androidx.work:work-runtime-ktx:$work_version"
백그라운에서 작업할 로직을 작성해주는 클래스이다.
이 클래스는 Worker 객체를 상속받아 작성되어야 하고, doWork라는 필수 멤버 메서드를 오버라이딩 해야 한다.
class UploadWorker(context: Context, params: WorkerParameters) : Worker(context,params) {
override fun doWork(): Result {
try {
for (i in 0..600) {
Log.i("MYTAG", "Uploading $i")
}
return Result.success()
} catch (e: Exception) {
return Result.failure()
}
}
}
0~600까지는 로그에 띄워주는 함수를 작성하였다.
private fun setOneTimeWorkRequest(){
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.build()
WorkManager.getInstance(applicationContext)
.enqueue(uploadRequest)
}
main에서 위와 같이 빌더를 만들어주고 worker class를 받아온다. 이 setOneTimeWorkRequest를 버튼에 onclick 함수로 넣어주면,
백그라운드 작업에서의 실행을 확인할 수 있다.
workManager의 작업 진행 경과를 liveData로 observing 할 수 있다.
실행함수를
private fun setOneTimeWorkRequest(){
val workManager = WorkManager.getInstance(applicationContext)
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.build()
workManager.enqueue(uploadRequest)
workManager.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this, Observer {
binding.textView.text = it.state.name
})
}
}
위와 같이 변경해보았다. workManager 인스턴스에 getWorkInfoByIdLiveData(builder.id)
를 확인하면 blocked, enqueued, running , succeeded 순으로 바뀌는 작업 상태를 확인할 수 있다.
constraints 는 작업의 규모가 클 때는 배터리가 많거나 충전중일 때만 작업을 실행하던지 하는 다양한 백그라운드 작업에 대비하여 걸어두는 제약사항이다.
사용방법은 아래와 같다.
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
그리고 그 작업에 enqueing 하는 uploadRequset에 .setConstraints 속성으로 넣어주면 된다.
private fun setOneTimeWorkRequest(){
val workManager = WorkManager.getInstance(applicationContext)
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.setConstraints(constraints)
.build()
workManager.enqueue(uploadRequest)
workManager.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this, Observer {
binding.textView.text = it.state.name
})
}
}
intent로 다른 클래스나 프래그먼트로 데이터를 보내는 것과 거의 유사한 방식으로 workManager를 하면서 데이터도 주고 받을 수 있다.
먼저 main -> worker class
외부에서 데이터를 보낼 때 정의한 키를 사용할 수 있도록 companion object로
companion object{
const val KEY_COUNT_VALUE = "key_count"
}
키를 만들어주고,
val data : Data = Data.Builder()
.putInt(KEY_COUNT_VALUE,125)
.build()
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.setConstraints(constraints)
.setInputData(data)
.build()
UploadRequest에 setInputData메서드로 data를 담아서 UploadWorker 클래스에 전달한다.
Worker Class 에서는
class UploadWorker(context: Context, params: WorkerParameters) : Worker(context,params) {
companion object{
const val KEY_WORKER = "key_worker"
}
override fun doWork(): Result {
try {
val count = inputData.getInt(MainActivity.KEY_COUNT_VALUE,0)
for (i in 0 until count) {
Log.i("MYTAG", "Uploading $i")
}
val time = SimpleDateFormat("dd/M/yyyy hh;mm;ss")
val currentDate = time.format(Date())
val outPutData = Data.Builder()
.putString(KEY_WORKER,currentDate)
.build()
return Result.success(outPutData)
} catch (e: Exception) {
return Result.failure()
}
}
}
마찬가지로 데이터를 보내기 위한 companion object를 만들고,
val count = inputData.getInt(MainActivity.KEY_COUNT_VALUE,0)
inputData를 감지하여 키에 해당하는 값을 가져온다.
이제 worker class -> main activity 로
데이터를 보내기 위해서는
val outPutData = Data.Builder()
.putString(KEY_WORKER,currentDate)
.build()
Data.Builder()안에 putString() 메서드로 데이터를 넣어주고,
return Result.success(outPutData)
result.success에 이를 담아주면 된다.