본문 바로가기
2023년 이전/Android

Android - WorkManager (6) - 취소, 반복작업, 고유 작업

by JeongUPark 2019. 10. 17.
반응형

이전 글 : 2019/10/17 - [프로그래밍/Android] - Android - WorkManager (5) - Chaining Work

출처-  Android developer - 취소, 반복작업, 고유작업

 

취소 및 중단

 

만약, 더 이상 이전에 enqueued한 동작중인 work가 필요 없을 경우, 그 작업을 취소 요청 할 수 있습니다.

가장 간단한 취소 방법은 다음과 같이 workRequest id로 취소요청을 하면 됩니다.

WorkManager.cancelWorkById(workRequest.id)

위의 취소 요청을 보내면, WorkManager는 work의 상태를 체크합니다. work가 이미 완료되었다면 아무일도 일어나지 않습니다. 그렇지 않으면 work의 상태가 CANCELED로 변경되어 다음번에 work가 동작하지 않습니다.

이 work에 종속된 모든 work이 다 취소 됩니다.

만약 work의 상태가 현재 RUNNING이라면, 이 work는 ListenableWorker.onStopped ()의 call도 받습니다. 잠재적인 처리를 위해 이 Method를 override 하면 됩니다.

또한, WorkManager.cancelAllWorkByTag (String)를 사용하여 태그로 WorkRequests를 취소 할 수도 있습니다. 이 메소드는 이 태그에 대한 모든 작업을 취소합니다. 또한 WorkManager.cancelUniqueWork (String)를 사용하여 고유 한 이름으로 모든 작업을 취소 할 수 있습니다.

 

WorkManager가 실행중인 work를 중지시키는 이유는 다음과 같습니다.

  • 명시 적으로 취소를 요청했습니다 (예 : WorkManager.cancelWorkById (UUID) 호출).
  • 고유 작업(unique work)의 경우 ExistingWorkPolicy가 REPLACE 인 새 WorkRequest를 명시 적으로 대기열에 추가했습니다. 이전 WorkRequest는 즉시 종료 된 것으로 간주됩니다.
  • 작업 제약 조건이 더 이상 충족되지 않습니다.
  • 시스템이 앱에 어떤 이유로 작업을 중지하도록 지시했습니다. 실행 기한 10 분을 초과하면 이런 일이 발생할 수 있습니다. 작업은 나중에 다시 시도하도록 예정(be scheduled)됩니다.

이러한 조건 하에서 woker은 ListenableWorker.onStopped ()로 부터 call을 받습니다. OS가 앱을 종료하기로 결정한 경우 cleanup을 수행하고 worker 마무리해야합니다. 또한 이미 중지되었는지 확인하고 싶을 때마다 ListenableWorker.isStopped ()를 참조하십시오.  마지막으로, onStopped ()가 호출 된 후 결과를 리턴하여 작업 완료를 알리더라도 작업자가 이미 중지 된 것으로 간주되므로 WorkManager는 해당 결과를 무시합니다.

 

반복작업

응용 프로그램이 시간이 특정 작업을 정기적으로 실행하는 것이 필요로 할 수있습니다. 예를 들어 주기적으로 데이터를 백업하거나 앱에서 최신 콘텐츠를 다운로드하거나 서버에 로그를 업로드 할 수 있습니다.

이런 주기적으로 실행해야하는 작업에는 PeriodicWorkRequest를 사용합니다.  PeriodicWorkRequest를 chaining할 수 없습니다. 작업에 chaining이 필요한 경우 OneTimeWorkRequest를 사용하면 됩니다.

 

다음은 작성 방법입니다.

이전 글에서 C WorkRqeust를 OneTimeWorkRequest에서 PeriodicWorkRequest로 변경하도록 하겠습니다.

MainFragment를 다음과 같이 변경합니다.

class MainFragment : Fragment() {

    companion object {
        fun newInstance() = MainFragment()
    }

    private lateinit var viewModel: MainViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.main_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

     	val C =  PeriodicWorkRequestBuilder<MyWorker_C>(3,TimeUnit.SECONDS).build()

        start_btn.setOnClickListener {
            WorkManager.getInstance(context!!).enqueue(C)
        }

    }

}

 

실행 하면 3초마다 반복해야 할 것 같지만 그렇지 않다. 그래서 code를 분석해보니

inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
    repeatInterval: Long,
    repeatIntervalTimeUnit: TimeUnit
): PeriodicWorkRequest.Builder {
    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval, repeatIntervalTimeUnit)
}
public Builder(
        @NonNull Class<? extends ListenableWorker> workerClass,
        long repeatInterval,
        @NonNull TimeUnit repeatIntervalTimeUnit) {
    super(workerClass);
    mWorkSpec.setPeriodic(repeatIntervalTimeUnit.toMillis(repeatInterval));
}

PeriodicWorkRequest를 빌드할 때 반복 주기가 들어가고, builder Method에서 setPeriodic을 통하여 반복 주기를 정하는데 아래 code를 보면 반복할 수 있는 최소 주기 MIN_PERIODIC_INTERVAL_MILLIS는 15분 입니다. 그리고  MIN_PERIODIC_FLEX_MILLIS라는 값이 있는데 이 값은 5분입니다. 이 Flex 주기가 어떤 역할을 하는지는 Android developer의 이곳 에서 참조하시면 될것 같습니다. (저도 정확히는 이해를 하지 못해서...)

/**
 * The minimum interval duration for {@link PeriodicWorkRequest} (in milliseconds).
 */
public static final long MIN_PERIODIC_INTERVAL_MILLIS = 15 * 60 * 1000L; // 15 minutes.
/**
 * The minimum flex duration for {@link PeriodicWorkRequest} (in milliseconds).
 */
public static final long MIN_PERIODIC_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes.

    .....

public void setPeriodic(long intervalDuration) {
     if (intervalDuration < MIN_PERIODIC_INTERVAL_MILLIS) {
         Logger.get().warning(TAG, String.format(
               "Interval duration lesser than minimum allowed value; Changed to %s",
                MIN_PERIODIC_INTERVAL_MILLIS));
        intervalDuration = MIN_PERIODIC_INTERVAL_MILLIS;
     }
     setPeriodic(intervalDuration, intervalDuration);
}

 .....

public void setPeriodic(long intervalDuration, long flexDuration) {
    if (intervalDuration < MIN_PERIODIC_INTERVAL_MILLIS) {
        Logger.get().warning(TAG, String.format(
                "Interval duration lesser than minimum allowed value; Changed to %s",
                MIN_PERIODIC_INTERVAL_MILLIS));
        intervalDuration = MIN_PERIODIC_INTERVAL_MILLIS;
    }
    if (flexDuration < MIN_PERIODIC_FLEX_MILLIS) {
        Logger.get().warning(TAG,
               String.format("Flex duration lesser than minimum allowed value; Changed to %s",
                       MIN_PERIODIC_FLEX_MILLIS));
        flexDuration = MIN_PERIODIC_FLEX_MILLIS;
    }
    if (flexDuration > intervalDuration) {
        Logger.get().warning(TAG,
                String.format("Flex duration greater than interval duration; Changed to %s",
                intervalDuration));
        flexDuration = intervalDuration;
    }
    this.intervalDuration = intervalDuration;
    this.flexDuration = flexDuration;
}

 

아무튼 시간은 지정한 시간과는 다르게 동작하였지만, 반복되는것은 확인 할 수 있습니다. 그리고 문서에서도

"반복 간격은 반복 사이의 최소 시간으로 정의됩니다. 작업자가 실행되는 정확한 시간은 작업 요청에 사용중인 제약 조건과 시스템에서 수행 한 최적화에 따라 다릅니다." 라고 설명되어 있습니다.

 

네 그렇습니다. 지정을 해도 지정한데로 반복 안할 수 있다는 말인것 같습니다. 그래서 제가 작성한 code를 실행하면

이런 결과를 보입니다.

고유작업

Unique Work는 한 번에 하나의 특정 이름을 가진 작업 체인 만 갖도록하는 강력한 개념입니다. ID와 달리 고유 이름은 사람이 읽을 수 있으며 WorkManager에 의해 자동 생성되는 대신 개발자가 지정합니다. 태그와 달리 고유 이름은 하나의 작업 체인에만 연관됩니다.

WorkManager.enqueueUniqueWork (String, ExistingWorkPolicy, OneTimeWorkRequest) 또는 WorkManager.enqueueUniquePeriodicWork (String, ExistingPeriodicWorkPolicy, PeriodicWorkRequest)를 호출하여 고유 한 작업 순서를 작성할 수 있습니다. 첫 번째 인수는 고유 한 이름입니다. 이는 WorkRequests를 식별하는 데 사용하는 키입니다. 두 번째 인수는 충돌 해결 정책으로, 고유 한 이름을 가진 완료되지 않은 작업 체인이있는 경우 WorkManager가 수행 할 작업을 지정합니다.

 

  • REPLACE : 기존 체인을 취소하고 새 체인으로 교체합니다.
  • KEEP : 기존 순서와 새 요청을 무시합니다.
  • APPEND : 기존 시퀀스의 마지막 작업이 완료된 후 새 시퀀스의 첫 번째 작업을 실행하여 새 시퀀스를 기존 시퀀스에 추가합니다. PeriodicWorkRequests와 함께 APPEND를 사용할 수 없습니다.

여러 번 대기열에 넣지 말아야 할 작업이있는 경우 Unique Work가 유용 할 수 있습니다. 예를 들어, 앱이 데이터를 네트워크에 동기화해야하는 경우 "sync"라는 시퀀스를 큐에 넣고 해당 이름의 시퀀스가 ​​이미있는 경우 새 작업을 무시하도록 지정할 수 있습니다. 긴 작업 체인을 점진적으로 구축해야하는 경우에도 Unique Work 순서가 유용 할 수 있습니다. 예를 들어 사진 편집 앱을 사용하면 긴 작업을 취소 할 수 있습니다. 각 실행 취소 작업은 시간이 걸릴 수 있지만 올바른 순서로 수행해야합니다.  이 경우 앱은 "실행 취소"체인을 생성하고 필요에 따라 각 실행 취소 작업을 체인에 추가 할 수 있습니다.

 

마지막으로 고유 한 작업 체인을 만들어야하는 경우 beginWith () 대신 WorkManager.beginUniqueWork (String, ExistingWorkPolicy, OneTimeWorkRequest)를 사용할 수 있습니다. 

반응형