İşleri yönetme

Worker ve WorkRequest tanımladıktan sonraki son adım, çalışmanızı sıraya almak olacaktır. İşleri sıraya almanın en basit yolu, çalıştırmak istediğiniz WorkRequest öğesini ileterek WorkManager enqueue() yöntemini çağırmaktır.

Kotlin

val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)

Java

WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);

Çalışmaları sıraya alırken yinelemeyi önlemek için dikkatli olun. Örneğin, bir uygulama günlüklerini her 24 saatte bir arka uç hizmetine yüklemeye çalışabilir. Dikkatli olmazsanız işin yalnızca bir kez çalışması gerekmesine rağmen aynı görevi birçok kez sıraya alabilirsiniz. Bu hedefe ulaşmak için işi benzersiz iş olarak planlayabilirsiniz.

Benzersiz Çalışma

Benzersiz çalışma, belirli bir adla aynı anda yalnızca bir çalışma örneğine sahip olmanızı garanti eden güçlü bir kavramdır. Kimliklerin aksine, benzersiz adlar insanlar tarafından okunabilir ve WorkManager tarafından otomatik olarak oluşturulmak yerine geliştirici tarafından belirtilir. Benzersiz adlar, etiketlerin aksine yalnızca tek bir çalışma örneğiyle ilişkilendirilir.

Benzersiz çalışma hem tek seferlik hem de düzenli çalışmalara uygulanabilir. Tekrarlanan bir iş veya tek seferlik bir iş planlamanıza bağlı olarak bu yöntemlerden birini çağırarak benzersiz bir iş sırası oluşturabilirsiniz.

Bu yöntemlerin her ikisi de 3 bağımsız değişken kabul eder:

  • uniqueWorkName: Çalışma isteğini benzersiz şekilde tanımlamak için kullanılan String.
  • existingWorkPolicy - Bu benzersiz ada sahip, tamamlanmamış bir iş zinciri zaten varsa WorkManager'a ne yapması gerektiğini söyleyen bir enum. Daha fazla bilgi için çakışma çözümü politikasına bakın.
  • work: Planlanacak WorkRequest.

Benzersiz çalışmalar kullanarak daha önce belirtilen yinelenen planlama sorunumuzu düzeltebiliriz.

Kotlin

val sendLogsWorkRequest =
       PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
           .setConstraints(Constraints.Builder()
               .setRequiresCharging(true)
               .build()
            )
           .build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
           "sendLogs",
           ExistingPeriodicWorkPolicy.KEEP,
           sendLogsWorkRequest
)

Java

PeriodicWorkRequest sendLogsWorkRequest = new
      PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
              .setConstraints(new Constraints.Builder()
              .setRequiresCharging(true)
          .build()
      )
     .build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
     "sendLogs",
     ExistingPeriodicWorkPolicy.KEEP,
     sendLogsWorkRequest);

Artık, bir sendLogs işi zaten kuyruktayken kod çalıştırılırsa mevcut iş korunur ve yeni bir iş eklenmez.

Uzun bir görev zinciri oluşturmanız gerektiğinde benzersiz iş sıraları da faydalı olabilir. Örneğin, bir fotoğraf düzenleme uygulaması, kullanıcıların uzun bir işlem zincirini geri almasına olanak tanıyabilir. Bu geri alma işlemlerinin her biri biraz zaman alabilir ancak doğru sırayla gerçekleştirilmeleri gerekir. Bu durumda uygulama, bir "geri alma" zinciri oluşturabilir ve her geri alma işlemini gerektiği gibi zincire ekleyebilir. Daha fazla bilgi için Çalışmaları zincirleme bölümüne bakın.

Çatışma çözümü politikası

Benzersiz bir iş planlarken WorkManager'a çakışma olduğunda hangi işlemi yapması gerektiğini söylemeniz gerekir. Bunu, işi sıraya alırken bir enum ileterek yaparsınız.

Tek seferlik işler için ExistingWorkPolicy sağlarsınız. Bu ExistingWorkPolicy, çakışmayı yönetmek için 4 seçeneği destekler.

  • REPLACE mevcut çalışmayı yeni çalışmayla karşılaştırın. Bu seçenek, mevcut çalışmayı iptal eder.
  • KEEP mevcut çalışmayı ve yeni çalışmayı yoksay.
  • APPEND yeni çalışmayı mevcut çalışmanın sonuna. Bu politika, yeni çalışmanızın mevcut çalışmaya bağlanmasına ve mevcut çalışma tamamlandıktan sonra çalışmasına neden olur.

Mevcut çalışma, yeni çalışmanın ön koşulu haline gelir. Mevcut çalışma CANCELLED veya FAILED olursa yeni çalışma da CANCELLED veya FAILED olur. Yeni işin mevcut işin durumundan bağımsız olarak çalışmasını istiyorsanız bunun yerine APPEND_OR_REPLACE kullanın.

  • APPEND_OR_REPLACE, APPEND ile benzer şekilde çalışır ancak ön koşul iş durumuyla ilişkili değildir. Mevcut çalışma CANCELLED veya FAILED ise yeni çalışma yine de çalışır.

Dönemlik çalışmalarda, REPLACE ve KEEP olmak üzere 2 seçeneği destekleyen bir ExistingPeriodicWorkPolicy sağlarsınız. Bu seçenekler, ExistingWorkPolicy karşılıklarıyla aynı şekilde çalışır.

Çalışmanızı gözlemleme

Çalışma sıraya alındıktan sonra, name, id veya ilişkili bir tag ile WorkManager'ı sorgulayarak durumunu istediğiniz zaman kontrol edebilirsiniz.

Kotlin

// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>

Java

// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>

Sorgu, ListenableFuture WorkInfo nesnesini döndürür. Bu nesne, çalışmanın id, etiketleri, mevcut State ve Result.success(outputData) kullanan tüm çıkış veri kümelerini içerir.

Her yöntemin LiveData ve Flow varyantları, bir dinleyici kaydederek WorkInfo değişikliklerini gözlemlemenizi sağlar. Örneğin, bazı işlemler başarıyla tamamlandığında kullanıcıya mesaj göstermek istiyorsanız bunu aşağıdaki gibi ayarlayabilirsiniz:

Kotlin

workManager.getWorkInfoByIdFlow(syncWorker.id)
          .collect{ workInfo ->
              if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
                  Snackbar.make(requireView(),
                      R.string.work_completed, Snackbar.LENGTH_SHORT)
                      .show()
              }
          }

Java

workManager.getWorkInfoByIdLiveData(syncWorker.id)
        .observe(getViewLifecycleOwner(), workInfo -> {
    if (workInfo.getState() != null &&
            workInfo.getState() == WorkInfo.State.SUCCEEDED) {
        Snackbar.make(requireView(),
                    R.string.work_completed, Snackbar.LENGTH_SHORT)
                .show();
   }
});

Karmaşık iş sorguları

WorkManager 2.4.0 ve sonraki sürümler, WorkQuery nesneleri kullanılarak sıraya alınmış işler için karmaşık sorgulamayı destekler. WorkQuery, etiketleri, durumu ve benzersiz iş adının kombinasyonuyla iş sorgulamayı destekler.

Aşağıdaki örnekte, FAILED veya CANCELLED durumunda olan ve"preProcess" ya da "sync" şeklinde benzersiz bir çalışma adına sahip "syncTag" etiketli tüm çalışmaları nasıl bulabileceğiniz gösterilmektedir.

Kotlin

val workQuery = WorkQuery.Builder
       .fromTags(listOf("syncTag"))
       .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(listOf("preProcess", "sync")
    )
   .build()

val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)

Java

WorkQuery workQuery = WorkQuery.Builder
       .fromTags(Arrays.asList("syncTag"))
       .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(Arrays.asList("preProcess", "sync")
     )
    .build();

ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);

Bir WorkQuery içindeki her bileşen (etiket, durum veya ad), diğerleriyle AND. Bir bileşendeki her değer OR ile ayrılır. Örneğin: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...).

WorkQuery, LiveData eşdeğeri olan getWorkInfosLiveData() ve Flow eşdeğeri olan getWorkInfosFlow() ile de çalışır.

Çalışmayı iptal etme ve durdurma

Daha önce sıraya aldığınız işinizin artık çalıştırılmasına gerek yoksa iptal edilmesini isteyebilirsiniz. Çalışma, name, id veya tag tarafından iptal edilebilir.

Kotlin

// by id
workManager.cancelWorkById(syncWorker.id)

// by name
workManager.cancelUniqueWork("sync")

// by tag
workManager.cancelAllWorkByTag("syncTag")

Java

// by id
workManager.cancelWorkById(syncWorker.id);

// by name
workManager.cancelUniqueWork("sync");

// by tag
workManager.cancelAllWorkByTag("syncTag");

WorkManager, arka planda çalışmanın State olup olmadığını kontrol eder. Çalışma tamamlanmışsa hiçbir şey olmaz. Aksi takdirde, işin durumu CANCELLED olarak değiştirilir ve iş gelecekte çalışmaz. WorkRequest işleri bu çalışmaya bağımlıysa onlar da CANCELLED olur.

RUNNING çalışanı ListenableWorker.onStopped() numaralı telefondan arama alıyor. Olası temizleme işlemlerini gerçekleştirmek için bu yöntemi geçersiz kılın. Daha fazla bilgi için çalışan bir işi durdurma başlıklı makaleyi inceleyin.

Çalışan bir Worker'ı durdurma

Çalışan Worker'nızın WorkManager tarafından durdurulmasının birkaç nedeni olabilir:

  • İptal edilmesini açıkça istediniz (örneğin, WorkManager.cancelWorkById(UUID) numaralı telefonu arayarak).
  • Benzersiz çalışma durumunda, REPLACE ExistingWorkPolicy ile yeni bir WorkRequest açıkça sıraya alınır. Eski WorkRequest hemen iptal edilmiş olarak kabul edilir.
  • Çalışmanızın kısıtlamaları artık karşılanmıyor.
  • Sistem, uygulamanıza çalışmayı durdurmasını söyledi. Bu durum, 10 dakikalık yürütme son tarihini aşarsanız meydana gelebilir. İşin daha sonra yeniden denenmesi planlanıyor.

Bu koşullar altında Worker'ınız durdurulur.

Devam eden tüm çalışmaları işbirliği içinde durdurmalı ve Worker'ınızın tuttuğu tüm kaynakları serbest bırakmalısınız. Örneğin, bu noktada veritabanları ve dosyalar için açık tutulan tutmaçları kapatmanız gerekir. Çalışanınızın ne zaman durduğunu anlamak için kullanabileceğiniz iki mekanizma vardır.

onStopped() geri çağırması

WorkManager, Worker'ınız durdurulur durdurulmaz ListenableWorker.onStopped()'ı çağırır. Elde tuttuğunuz kaynakları kapatmak için bu yöntemi geçersiz kılın.

isStopped() özelliği

Çalışanınızın durdurulup durdurulmadığını kontrol etmek için ListenableWorker.isStopped() yöntemini çağırabilirsiniz. Worker'ınızda uzun süren veya tekrarlanan işlemler gerçekleştiriyorsanız bu özelliği sık sık kontrol etmeli ve mümkün olan en kısa sürede çalışmayı durdurmak için bir sinyal olarak kullanmalısınız.

Not: WorkManager, onStop sinyalini almış bir Worker tarafından ayarlanan Result değerini yoksayar. Bunun nedeni, Worker'ın zaten durdurulmuş olarak kabul edilmesidir.

Durdurma nedeni durumunu gözlemleme

Worker öğesinin neden durdurulduğunu ayıklamak için WorkInfo.getStopReason() işlevini çağırarak durdurma nedenini günlüğe kaydedebilirsiniz:

Kotlin

workManager.getWorkInfoByIdFlow(syncWorker.id)
  .collect { workInfo ->
      if (workInfo != null) {
        val stopReason = workInfo.stopReason
        logStopReason(syncWorker.id, stopReason)
      }
  }

Java

  workManager.getWorkInfoByIdLiveData(syncWorker.id)
    .observe(getViewLifecycleOwner(), workInfo -> {
        if (workInfo != null) {
          int stopReason = workInfo.getStopReason();
          logStopReason(syncWorker.id, workInfo.getStopReason());
        }
  });