개발모음집

Android WorkManager 본문

Android

Android WorkManager

void 2019. 5. 10. 10:00

안드로이드 서비스부터 봐야한다.

 

서비스 발전 : 서비스 -> 서비스(doze모드 도입) -> JobScheduler -> Firebase JobDispatcher -> workmanager

 

workmanager가 생긴 이유?

프로세스에서 진행되기에 (앱을 실행안시키고 있어도 계속 동작하니까) 자원낭비가 심하고 배터리소모도 심했다. )
-> 마시멜로 버전에서 doze 모드 도입 (앱이 꺼져도유저가 디바이스의 스크린을 끄고나면, 도즈모드가 시작되어 네트워크 통신, Sync, GPS, 알람, 와이파이 스캔 등을 비활성화 시켜버립니다. 이 도즈모드는 사용자가 스크린을 켜거나, 디바이스를 충전기에 연결할 때까지 유지됩니다.)
-> 결국엔 프로세스에서 동작하니까, JobScheduler라는걸 추가 ( 서브스레드에서 동작하는지는 확인해봐야함)
하지만 JobScheduler는 API21 이상만 동작가능
그래서 API9이상 동작가능한 Firebase JobDispatcher가 나왔는데 Google Play Services가 기기에 설치되어야하는 등의 제약사항이 있어 중국폰이나 여러 기타폰에선 사용하지못함.
-> 그래서 workmanager가 나옴.

 

WorkManager란?

앱이 종료되거나 기기가 다시 시작되더라도 실행이 예상되는 연기 가능한 비동기 작업을 쉽게 예약할 수 있는 라이브러리

예) 로그
데이터를 서버와 주기적으로 동기화
사진 업로드

서비스와 차이점?

앱의 process 안의 새로운 thread에서 task를 실행시킬 수 있습니다
 출처: https://emong.tistory.com/211 [에몽이]

WorkManager 의 작업은 반드시 실행되지만 그 처리가 상황에 따라 지연 되거나 도중에 중단될 경우 다시 실행 될수 있다는 것을 꼭 기억해야 합니다.

출처 : https://medium.com/@limgyumin/%EC%83%88%EB%A1%9C%EC%9A%B4-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EB%B0%B1%EA%B7%B8%EB%9D%BC%EC%9A%B4%EB%93%9C-%EC%9E%91%EC%97%85-%EC%B2%98%EB%A6%AC%EB%B2%95-workmanager-f625e07b384c

 

언제 WorkManager를 사용해야할 것인가?

https://developer.android.com/guide/background/

 

꼭 백그라운드 동작을 할 때 WorkManager를 써야하는 건 아니다.

HTTP를 통해 큰 파일 다운로드를 받으면 DownloadManager
연기할 수 없는 일이면, ForegroundService (UI)
앱의 동작이 꺼져도 동작해야하는 기능이 있으면  WorkManager
시스템상태에 따라 발생하는 기능이면 workManager
정확한 시간대에 실행을 해야한다면, AlarmManager
출처 : https://developer.android.com/guide/background/

workManager 주요 클래스 특징

  • WorkManager : 인수 / 제약조건을 가진 작업을 받아서, 큐에 추가합니다.
  • Worker : 백그라운드 스레드에서 동작하는 doWork() 메서드 하나만 가지고 있습니다. 모든 백그라운드 태스크들은 이 메서드 안에서 수행되어야 합니다. 가능한한 심플하도록 구성해야 합니다.
  • WorkRequest : Worker가 어떤 인수와 제약조건(ex : 인터넷, 충전 등)와 함께 큐에 추가되어야할지를 명시하는 역할입니다.
  • WorkResult : 성공, 실패, 재시도
  • Data : Worker로 주고받는 영구적인 키-벨류 쌍의 값 입니다.

참고: http://dktfrmaster.blogspot.com/2018/06/workmanager.html

WorkManager 사용법

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

   
override fun doWork(): Result {
       
// Do the work here--in this case, upload the images.

        uploadImages
()

       
// Indicate whether the task finished successfully with the Result
       
return Result.success()
   
}
}

 

val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
       
.build()

 

WorkManager.getInstance().enqueue(uploadWorkRequest)

출처 : https://developer.android.com/topic/libraries/architecture/workmanager/basics.html

 

private fun callLogWorker(startTime: Long) {

// 코드 참고 : https://android--code.blogspot.com/2019/02/android-kotlin-workmanager-input-output.html
// 출처 : https://emong.tistory.com/211#recentEntries
val data = Data.Builder()
data.putLong("startTime", startTime)


val logWork = OneTimeWorkRequestBuilder<LogWorker>().setInputData(data.build()).build()
// Create an one time work request

// Enqueue the work
WorkManager.getInstance(APP.context()).enqueue(logWork)

WorkManager.getInstance(APP.context()).getWorkInfoByIdLiveData(logWork.id)
.observe(this, Observer { workInfo ->

if (workInfo != null) {
if (workInfo.state == WorkInfo.State.ENQUEUED) {
// Show the work state in text view
logDebug(ONRESUME, "Download enqueued.")
} else if (workInfo.state == WorkInfo.State.BLOCKED) {
logDebug(ONRESUME, "Download blocked.")
} else if (workInfo.state == WorkInfo.State.RUNNING) {
logDebug(ONRESUME, "Download running.")
}
}

// When work finished
if (workInfo != null && workInfo.state.isFinished) {
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
logDebug(ONRESUME, "Download successful.")

// Get the output data
val successOutputData = workInfo.outputData

// workmanager에서 넘어온 값받아오는 코드
startTime?.apply {
// logDebug(ONRESUME, uriText)
}
} else if (workInfo.state == WorkInfo.State.FAILED) {
logDebug(ONRESUME, "Failed to download.")
} else if (workInfo.state == WorkInfo.State.CANCELLED) {
logDebug(ONRESUME, "Work request cancelled.")
}
}

})
}

 



// WorkManager의 공식 홈페이지 : https://developer.android.com/jetpack/androidx/releases/work
// TODO : 앱의 실행시간을 SQLite에 저장하고 서버에 전달함.
class LogWorker(appContext: Context, workerParams: WorkerParameters)
: Worker(appContext, workerParams) {

val TAG = "LogWorker"
val onResume = "onResume"
val APP = FestivalApplication.instance
val lifecycleName = inputData.getString("Log")
private val zero : Long = 0
// 앱 시작 시간
var startTime : Long = zero
// 앱 종료 시간
private var endTime: Long = zero
// 실행 시간
private var elapsedTime: Long = zero
// 실행시간(시 분 초 형식)
private var elapsedTimeStr: String = ""


override fun doWork(): Result {

// 메인 액티비티의 onResume 메서드에서 앱 실행 시간을 체크함.
// 앱이 실행중이면서 MainActivity의 onResume에서 호출한 Work라면, 시작시간을 부름
/* if (APP.isAppRunning() and onResume.equals(lifecycleName)) {

startTime = System.currentTimeMillis()
logDebug(TAG+"activityResumed", "현재 "+TAG +"의 시작시간은 " +startTime + "입니다. 기기번호는 " + APP.getAndroidUniqueId())

}else {
*/
// App is not running
startTime = inputData.getLong("startTime", 0)
endTime = System.currentTimeMillis()

// 0초라면 처음 실행한 거니까
if (elapsedTime == zero) {
elapsedTime = endTime - startTime
logError(TAG, "startTime:" + startTime + ",endTime:" + endTime + ",elapsedTime:" + elapsedTime)

} else {
// 0이 아니라면, 기존의 경과시간 + 이번에 앱실행 시간
val priorTime = endTime - startTime
elapsedTime = priorTime + elapsedTime
logError(TAG, "startTime:" + startTime + ",endTime:" + endTime + ",elapsedTime:" + elapsedTime + ".priorTime:" + priorTime)
}

val formatter = SimpleDateFormat("ss", Locale.KOREA)
elapsedTimeStr = formatter.format(elapsedTime)

logDebug(
TAG + "activityPaused",
"현재 " + TAG + "의 종료시간은 " + endTime + "입니다. 그리고 실행시간은 " + elapsedTimeStr + "입니다."
)




logDebug(TAG, "result.success"+startTime)
return Result.success()
}

// WorkManager를 호출한 액티비티로 데이터 반환
private fun createOutputData(startTime: Long): Data {
return Data.Builder()
.putLong("startTime", startTime)
.build()
}

 

 

 

 

 

 

 

 

참고 :

1. 안드로이드 버전 : 킷캣 -> 롤리팝 -> 마시멜로 ->누가 -> 오레오 -> 파이

2. BroadcastReceiver 를 통해서 기기의 부팅, 네트워크 연결 등의 
디바이스 이벤트를 시스템으로부터 전파받아서 특정 작업을 수행해왔는데 
누가 버전에서 특정 인텐트에 대해 동작이 제한되고, 오레오 버전에서 암시적 브로드캐스트리시버 등록을 차단하는 등 
제한이 추가되고 있습니다. 

출처: https://duzi077.tistory.com/222 [개발하는 두더지]

3. 안드로이드 workmanager 사용법
깃헙자료 https://github.com/googlecodelabs/android-workmanager

https://codelabs.developers.google.com/codelabs/android-workmanager/#11

4. workmanager 버전
출처 : https://developer.android.com/jetpack/androidx/releases/archive/arch