본문 바로가기

[Android] WorkManager를 활용해 주기적인 백그라운드 작업 실행하기 (15min ver)

@hyeon.s2024. 7. 23. 22:16

지속적인 디버깅 탐지 (15min ver)

WorkManager의 이슈 발생

  1. Workmanager의 주기를 15분으로 설정했으나 15분보다 더 짧은 시간에 work 발생
  2. 앱 실행시 동시다발적으로 여러개의 work 발생

문제상황 인식 및 분석

1. MainActivity에 생성한 detectDebug WorkManager의 WorkInfo의 state를 살펴봄
⇒ 여러개의 work가 한번에 enqueue되고, doWork()가 실행되는 것을 볼 수 있었음.

2. Application에 등록한 createWorkManager가 여러번 실행되는 것인가? 라고 생각 함
⇒ Application의 onCreate(), createWorkManager()의 함수 호출을 확인해 봄

15분보다는 짧은 시간에 수행되어서 장점이라고 생각할 수 있지만. 여러 문제를 일으킬 수 있는 여지가 있다.

  1. dowork()가 실행되어서 tracerPid를 감지할 때, 만약 tracerPid ≠ 0인 상태라면 문제가 생긴다.
    • dowork()가 동시다발적으로 많이 수행되기 때문에 여러번 finish()가 수행되어서 앱이 렉걸린거 처럼 여러번 종료되는 모습이 발생했다.
  2. 기대하지 않은 workManager의 주기로 프로세스에도 영향을 줄 수 있다.

⇒ 즉 workManager가 제대로된 순서와 주기로 실행되도록 오류를 해결해야한다.

해결방법

  1. PeriodicWorkRequest의 enqueue 방법 수정
  2. workManager가 꼬이지 않도록 실행 전 WorkInfo List 확인
  3. WorkManager 공식문서 바탕으로 stable한 최신 버전으로 업데이트
  4. application onTerminate()시에 All work cancel지속적인 디버깅 탐지 (15min ver)
    1. -> application의 onTerminate()는 실제 어플이 종료될 때 사용되기보다는 하드웨어가 종료될 때 사용된다고 해서 효과가 없는 방법이였다. 

createDetectDebugWorkManager()

이전코드

// 중략
    private void createDetectDebugWorkManager(){
        PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
                DebugDetectWorker.class,15, TimeUnit.MINUTES // 주기 15분
        ).build();
        WorkManager.getInstance(this).enqueue(workRequest);
    }  // WorkManager 생성

수정코드

private void createDetectDebugWorkManager() {
        PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
                DebugDetectWorker.class, 15, TimeUnit.MINUTES
        ).addTag("detectDebug").build();
        WorkManager.getInstance(this).enqueueUniquePeriodicWork("detectDebug", ExistingPeriodicWorkPolicy.KEEP, workRequest);
    }

바뀐점

해당 WorkManager는 주기적으로 실행하는 PeriodicWorkManager이다.
따라서 WorkRequest를 생성하고 enqueue하는 방식을 그냥 enqueue가 아닌 enqueueUniquePeriodicWork를 사용해야한다.

또한 enqueue하는 방식의 정책을 ExistingPeriodicWorkPolicy.KEEP으로 설정한다.
→ 이렇게 설정하면 이미 detectDebug work이 있다면 추가적으로 들어오는 enqueue에 대해서 취소 처리를 한다.

checkEnqueue()

WorkList가 꼬이지 않도록, 비어있을 때만 enqueue 하도록 하는 함수이다.

 private void checkEnqueue() throws ExecutionException, InterruptedException {
        WorkManager workmanager = WorkManager.getInstance(this);
        List<WorkInfo> workInfoList = workmanager.getWorkInfosForUniqueWork("detectDebug").get();
        if (workInfoList.isEmpty()){
            createDetectDebugWorkManager();
            Log.e("hyeon","work info list empty");
        }
    } 

해당 함수는 get 하는 과정에서 Exception을 발생시키기 때문에 Application onCreate()에서 실행할 때 Exception처리를 해야한다.

App.onCreate()

  @Override
    public void onCreate() {
        super.onCreate();
        UsbConnectionReceiver.registerReceiver(this, usbReceiver);
        try {
            checkEnqueue();
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    } // 발생하는 exception에 따라서 예외를 처리하면 된다. 

WorkManager 최신 버전 업데이트

build.gradle

 // Workmanager
    implementation("androidx.work:work-runtime:2.9.0")

App.onTerminate()

 @Override
    public void onTerminate() {
        super.onTerminate();
        UsbConnectionReceiver.unregisterReceiver(this, usbReceiver);
        WorkManager.getInstance(this).cancelAllWorkByTag("detectDebug"); 
        // application 종료 시 all wrok cancel
    }

구현결과

수정한 결과 15분 간격으로 알맞게 workManager가 실행되는걸 볼 수 있다.
tracerPid =1로 직접 바꿨을 때도 앱이 강제종료되는 것을 볼 수 있었다.

15분보다 더 미만으로 작업을 수행하는 코드는 다음시간에 ..

레퍼런스

Android Developer WorkManager 작업관리

WorkManager  |  Jetpack  |  Android Developers

https://github.com/android/codelab-android-workmanager/issues/99

https://velog.io/@shin75492/kotlin-workmanager와-백그라운드-작업

 

hyeon.s
@hyeon.s :: 개발로그
목차