İş isteklerini tanımlama

Başlangıç kılavuzunda, WorkRequest oluşturma ve sıraya ekleme işlemleri ele alınmıştı.

Bu kılavuzda, yaygın kullanım alanlarını ele almak için WorkRequest nesnelerini nasıl tanımlayacağınızı ve özelleştireceğinizi öğreneceksiniz. Örneğin:

  • Tek seferlik ve yinelenen işleri planlama
  • Kablosuz bağlantı veya şarj gerektirme gibi çalışma kısıtlamaları ayarlama
  • İşlerin yürütülmesinde minimum gecikmeyi garanti etme
  • Yeniden deneme ve bekleme stratejileri belirleme
  • Giriş verilerini işe aktarma
  • Etiketleri kullanarak ilgili çalışmaları gruplandırma

Genel Bakış

WorkManager'da iş, WorkRequest kullanılarak tanımlanır. WorkManager ile herhangi bir iş planlamak için önce bir WorkRequest nesnesi oluşturmanız ve ardından bunu sıraya eklemeniz gerekir.

Kotlin

val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)

Java

WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);

WorkRequest nesnesi, WorkManager'ın çalışmanızı planlamak ve çalıştırmak için ihtiyaç duyduğu tüm bilgileri içerir. İşinizin çalışması için karşılanması gereken kısıtlamaları, gecikmeler veya tekrarlama aralıkları gibi planlama bilgilerini, yeniden deneme yapılandırmasını ve işiniz buna bağlıysa giriş verilerini içerir.

WorkRequest, soyut bir temel sınıftır. İsteği oluşturmak için kullanabileceğiniz bu sınıfın iki türetilmiş uygulaması vardır: OneTimeWorkRequest ve PeriodicWorkRequest. Adlarından da anlaşılacağı üzere OneTimeWorkRequest, tekrarlanmayan işleri planlamak için kullanışlıdır. PeriodicWorkRequest ise belirli aralıklarla tekrarlanan işleri planlamak için daha uygundur.

Tek seferlik çalışma planlama

Ek yapılandırma gerektirmeyen temel işlemler için statik yöntemi from kullanın:

Kotlin

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

Java

WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);

Daha karmaşık işler için bir oluşturucu kullanabilirsiniz:

Kotlin

val uploadWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       // Additional configuration
       .build()

Java

WorkRequest uploadWorkRequest =
   new OneTimeWorkRequest.Builder(MyWork.class)
       // Additional configuration
       .build();

Yüksek öncelikli işleri planlama

WorkManager 2.7.0, yüksek öncelikli iş kavramını kullanıma sundu. Bu sayede WorkManager, önemli işleri yürütürken sistemin kaynaklara erişim üzerinde daha iyi kontrol sahibi olmasını sağlar.

Yüksek öncelikli işler aşağıdaki özellikleriyle öne çıkar:

  • Önem: Yüksek öncelikli iş, kullanıcı için önemli olan veya kullanıcı tarafından başlatılan görevler için uygundur.
  • Hız: Yüksek öncelikli iş, hemen başlayan ve birkaç dakika içinde tamamlanan kısa görevler için en uygun seçenektir.
  • Kotalar: Ön planda yürütme süresini sınırlayan sistem düzeyinde bir kota, yüksek öncelikli bir işin başlayıp başlayamayacağını belirler.
  • Güç Yönetimi: Pil Tasarrufu ve Doze gibi güç yönetimi kısıtlamalarının yüksek öncelikli işleri etkileme olasılığı daha düşüktür.
  • Gecikme: Sistem, mevcut iş yükü izin verdiği sürece yüksek öncelikli işleri hemen yürütür. Bu, yüksek öncelikli işlerin gecikmeye duyarlı olduğu ve daha sonra yürütülmek üzere planlanamayacağı anlamına gelir.

Yüksek öncelikli iş, kullanıcının mesaj veya ekli resim göndermek istediği bir sohbet uygulamasında kullanılabilir. Benzer şekilde, ödeme veya abonelik akışını yöneten bir uygulama da yüksek öncelikli işleri kullanmak isteyebilir. Bu görevler kullanıcı için önemlidir, arka planda hızlı bir şekilde yürütülür, hemen başlatılması gerekir ve kullanıcı uygulamayı kapatsa bile yürütülmeye devam etmelidir.

Kotalar

Sistemin, yüksek öncelikli bir işi çalıştırabilmesi için yürütme süresi ayırması gerekir. Yürütme süresi sınırsız değildir. Bunun yerine her uygulamaya bir yürütme süresi kotası verilir. Uygulamanız yürütme süresini kullanıp tahsis edilen kotasına ulaştığında, kota yenilenene kadar yüksek öncelikli işleri yürütemezsiniz. Bu sayede Android, uygulamalar arasında kaynakları daha etkili bir şekilde dengeleyebilir.

Bir uygulamanın kullanabileceği yürütme süresi, bekleme grubuna ve işlemin önemine bağlıdır.

Yürütme kotası, yüksek öncelikli bir işin hemen çalıştırılmasına izin vermediğinde ne olacağını belirleyebilirsiniz. Ayrıntılar için aşağıdaki snippet'lere bakın.

Yüksek öncelikli işleri yürütme

WorkManager 2.7'den itibaren uygulamanız, yüksek öncelikli iş kullanarak WorkRequest öğesinin mümkün olduğunca hızlı çalışması gerektiğini bildirmek için setExpedited() yöntemini çağırabilir. Aşağıdaki kod snippet'inde setExpedited() öğesinin nasıl kullanılacağına dair bir örnek verilmiştir:

Kotlin

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    <b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
    .build()

WorkManager.getInstance(context)
    .enqueue(request)

Java

OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
    .setInputData(inputData)
    <b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
    .build();

Bu örnekte, bir OneTimeWorkRequest örneği başlatıp bu örnekte setExpedited() yöntemini çağırıyoruz. Bu istek daha sonra yüksek öncelikli iş haline gelir. Kota izin veriyorsa arka planda hemen çalışmaya başlar. Kota kullanıldıysa OutOfQuotaPolicy parametresi, isteğin normal, yüksek öncelikli olmayan bir iş olarak çalıştırılması gerektiğini gösterir.

Geriye dönük uyumluluk ve ön plan hizmetleri

WorkManager, yüksek öncelikli işler için geriye dönük uyumluluğu korumak amacıyla Android 12'den eski platform sürümlerinde ön plan hizmeti çalıştırabilir. Ön plan hizmetleri, kullanıcıya bildirim gösterebilir.

Worker'ınızdaki getForegroundInfoAsync() ve getForegroundInfo() yöntemleri, Android 12'den önceki sürümlerde setExpedited() yöntemini çağırdığınızda WorkManager'ın bildirim göstermesini sağlar.

Görevin yüksek öncelikli iş olarak çalıştırılmasını talep etmek istiyorsanız tüm ListenableWorker sınıflarının getForegroundInfo yöntemini uygulaması gerekir.

Android 12 veya sonraki sürümleri hedeflediğinizde ön plan hizmetleri, ilgili setForeground yöntemi aracılığıyla kullanılabilir durumda kalır.

Çalışan

Çalışanlar, yaptıkları işin hızlandırılıp hızlandırılmadığını bilmez. Ancak çalışanlar, Android'in bazı sürümlerinde bir WorkRequest hızlandırıldığında bildirim gösterebilir.

WorkManager, bu özelliği etkinleştirmek için getForegroundInfoAsync() yöntemini sağlar. WorkManager'ın gerektiğinde sizin için bir ForegroundService başlatmak üzere bildirim gösterebilmesi için bu yöntemi uygulamanız gerekir.

CoroutineWorker

CoroutineWorker kullanıyorsanız getForegroundInfo() uygulamanız gerekir. Ardından, doWork() içinde setForeground() yöntemine iletirsiniz. Bu işlem, Android 12'den önceki sürümlerde bildirimi oluşturur.

Aşağıdaki örneği inceleyelim:

  class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
   CoroutineWorker(appContext, workerParams) {

   override suspend fun getForegroundInfo(): ForegroundInfo {
       return ForegroundInfo(
           NOTIFICATION_ID, createNotification()
       )
   }

   override suspend fun doWork(): Result {
       TODO()
   }

    private fun createNotification() : Notification {
       TODO()
    }

}

Kota politikaları

Uygulamanız yürütme kotasına ulaştığında yüksek öncelikli işlere ne olacağını kontrol edebilirsiniz. Devam etmek için setExpedited() parametresini iletebilirsiniz:

  • OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST. Bu da işin sıradan bir iş isteği olarak çalıştırılmasına neden olur. Önceki snippet bunu göstermektedir.
  • OutOfQuotaPolicy.DROP_WORK_REQUEST. Bu nedenle, yeterli kota yoksa istek iptal edilir.

Ertelenen yüksek öncelikli işler

Sistem, belirli bir yüksek öncelikli işi, iş çağrıldıktan sonra mümkün olan en kısa sürede yürütmeye çalışır. Ancak diğer iş türlerinde olduğu gibi, sistem yeni yüksek öncelikli işlerin başlatılmasını aşağıdaki durumlarda erteleyebilir:

  • Yük: Sistem yükü çok yüksek. Bu durum, çok fazla iş zaten çalışıyorsa veya sistemde yeterli bellek yoksa ortaya çıkabilir.
  • Kota: Yüksek öncelikli iş kotası sınırı aşıldı. Yüksek öncelikli iş, Uygulamayı Beklemeye Alma Grupları'nı temel alan bir kota sistemi kullanır ve sürekli zaman aralığında maksimum yürütme süresini sınırlandırır. Yüksek öncelikli işler için kullanılan kotalar, diğer arka plan işleri için kullanılan kotalardan daha kısıtlayıcıdır.

Periyodik çalışma planlama

Uygulamanız bazen belirli işlemlerin düzenli olarak çalıştırılmasını gerektirebilir. Örneğin, verilerinizi düzenli olarak yedeklemek, uygulamanıza yeni içerik indirmek veya günlükleri bir sunucuya yüklemek isteyebilirsiniz.

Periyodik olarak yürütülen bir WorkRequest nesnesi oluşturmak için PeriodicWorkRequest'ı şu şekilde kullanabilirsiniz:

Kotlin

val saveRequest =
       PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
    // Additional configuration
           .build()

Java

PeriodicWorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
           // Constraints
           .build();

Bu örnekte, çalışma bir saatlik aralıklarla planlanmıştır.

Aralık süresi, tekrarlar arasındaki minimum süre olarak tanımlanır. Çalışanın tam olarak ne zaman yürütüleceği, WorkRequest nesnenizde kullandığınız kısıtlamalara ve sistem tarafından gerçekleştirilen optimizasyonlara bağlıdır.

Esnek çalıştırma aralıkları

İşinizin niteliği nedeniyle çalışma zamanlaması hassassa PeriodicWorkRequest öğenizi, Şekil 1'de gösterildiği gibi her aralık döneminde bir esnek dönem içinde çalışacak şekilde yapılandırabilirsiniz.

Periyodik bir iş için esnek aralık ayarlayabilirsiniz. Tekrar aralığı ve tekrar aralığının sonunda belirli bir süreyi belirten esnek aralık tanımlarsınız. WorkManager, her döngüdeki esnek aralık sırasında bir noktada işinizi çalıştırmayı dener.

Şekil 1. Diyagramda, işin çalışabileceği esnek dönemi içeren yinelenen aralıklar gösterilmektedir.

Esnek dönemli periyodik iş tanımlamak için PeriodicWorkRequest oluştururken repeatInterval ile birlikte flexInterval iletirsiniz. Esnek dönem repeatInterval - flexInterval tarihinde başlar ve aralığın sonuna kadar devam eder.

Aşağıda, her bir saatlik dönemin son 15 dakikasında çalıştırılabilen periyodik iş örneği verilmiştir.

Kotlin

val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
       1, TimeUnit.HOURS, // repeatInterval (the period cycle)
       15, TimeUnit.MINUTES) // flexInterval
    .build()

Java

WorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
               1, TimeUnit.HOURS,
               15, TimeUnit.MINUTES)
           .build();

Tekrar aralığı PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS değerinden büyük veya bu değere eşit olmalıdır. Esnek aralık ise PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS` değerinden büyük veya bu değere eşit olmalıdır.

Kısıtlamaların Periyodik Çalışma Üzerindeki Etkisi

Periyodik çalışmalara kısıtlamalar uygulayabilirsiniz. Örneğin, iş isteğinize bir kısıtlama ekleyerek işin yalnızca kullanıcının cihazı şarj olurken çalışmasını sağlayabilirsiniz. Bu durumda, tanımlanan tekrar aralığı geçse bile bu koşul karşılanana kadar PeriodicWorkRequest çalıştırılmaz. Bu durum, çalışmanızın belirli bir çalıştırmasının gecikmesine, hatta koşullar çalıştırma aralığında karşılanmazsa atlanmasına neden olabilir.

İş kısıtlamaları

Constraints, işin en uygun koşullar sağlanana kadar ertelenmesini sağlar. WorkManager'da aşağıdaki kısıtlamalar kullanılabilir:

NetworkType Çalışmanızın yürütülmesi için gereken ağ türünü kısıtlar. Örneğin, kablosuz ağ (UNMETERED).
BatteryNotLow "True" olarak ayarlanırsa cihaz düşük pil modundayken çalışmanız yürütülmez.
RequiresCharging "Doğru" olarak ayarlandığında çalışmanız yalnızca cihaz şarj olurken çalışır.
DeviceIdle Bu değer doğru olarak ayarlandığında, işin çalıştırılabilmesi için kullanıcının cihazının boşta olması gerekir. Bu, kullanıcının cihazında etkin olarak çalışan diğer uygulamaların performansını olumsuz etkileyebilecek toplu işlemleri çalıştırmak için yararlı olabilir.
StorageNotLow "True" olarak ayarlandığında, kullanıcının cihazdaki depolama alanı çok azsa çalışmanız yürütülmez.

Bir kısıtlama grubu oluşturmak ve bunu bir çalışmayla ilişkilendirmek için Constraints.Builder() kullanarak bir Constraints örneği oluşturun ve bunu WorkRequest.Builder() öğenize atayın.

Örneğin, aşağıdaki kod, yalnızca kullanıcının cihazı hem şarj olurken hem de kablosuz ağa bağlıyken çalışan bir iş isteği oluşturur:

Kotlin

val constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.UNMETERED)
   .setRequiresCharging(true)
   .build()

val myWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       .setConstraints(constraints)
       .build()

Java

Constraints constraints = new Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresCharging(true)
       .build();

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setConstraints(constraints)
               .build();

Birden fazla kısıtlama belirtildiğinde çalışmanız yalnızca tüm kısıtlamalar karşılandığında çalıştırılır.

İşiniz çalışırken bir kısıtlama karşılanmazsa WorkManager, çalışanınızı durdurur. Tüm kısıtlamalar karşılandığında iş yeniden denenir.

Gecikmeli Çalışma

Çalışmanızın kısıtlaması yoksa veya çalışmanız sıraya alındığında tüm kısıtlamalar karşılanıyorsa sistem, çalışmayı hemen çalıştırmayı seçebilir. İşin hemen çalıştırılmasını istemiyorsanız işinizin minimum bir ilk gecikmeden sonra başlayacağını belirtebilirsiniz.

Aşağıda, çalışmanızı sıraya alındıktan en az 10 dakika sonra çalışacak şekilde nasıl ayarlayacağınıza dair bir örnek verilmiştir.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()

Java

WorkRequest myWorkRequest =
      new OneTimeWorkRequest.Builder(MyWork.class)
               .setInitialDelay(10, TimeUnit.MINUTES)
               .build();

Örnekte OneTimeWorkRequest için ilk gecikmenin nasıl ayarlanacağı gösterilse de PeriodicWorkRequest için de ilk gecikme ayarlayabilirsiniz. Bu durumda, periyodik işinizin yalnızca ilk çalıştırılması geciktirilir.

Yeniden deneme ve geri yükleme politikası

WorkManager'ın çalışmanızı yeniden denemesini istiyorsanız çalışanınızdan Result.retry() döndürebilirsiniz. Ardından, çalışmanız gecikme süresi ve gecikme politikasına göre yeniden planlanır.

  • Geri çekilme gecikmesi, ilk denemeden sonra çalışmanızı yeniden denemeden önce beklenecek minimum süreyi belirtir. Bu değer 10 saniyeden (veya MIN_BACKOFF_MILLIS) az olamaz.

  • Geri çekilme politikası, sonraki yeniden deneme girişimleri için geri çekilme gecikmesinin zaman içinde nasıl artması gerektiğini tanımlar. WorkManager, 2 geri çekilme politikasını destekler: LINEAR ve EXPONENTIAL.

Her iş isteğinin bir bekleme politikası ve bekleme gecikmesi vardır. Varsayılan politika 30 saniyelik gecikmeyle EXPONENTIAL şeklindedir ancak iş isteği yapılandırmanızda bunu geçersiz kılabilirsiniz.

Aşağıda, geri çekilme gecikmesini ve politikasını özelleştirmeyle ilgili bir örnek verilmiştir.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       WorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setBackoffCriteria(
                       BackoffPolicy.LINEAR,
                       WorkRequest.MIN_BACKOFF_MILLIS,
                       TimeUnit.MILLISECONDS)
               .build();

Bu örnekte, minimum geri çekilme gecikmesi izin verilen minimum değer olan 10 saniyeye ayarlanmıştır. Politika LINEAR olduğundan, yeniden deneme aralığı her yeni denemede yaklaşık 10 saniye artar. Örneğin, Result.retry() ile biten ilk çalıştırma 10 saniye sonra tekrar denenir. Sonraki denemelerden sonra çalışma Result.retry() döndürmeye devam ederse 20, 30, 40 saniye vb. aralıklarla denemeler yapılır. Geri çekilme politikası EXPONENTIAL olarak ayarlanırsa yeniden deneme süresi sırası 20, 40 ve 80'e daha yakın olur.

Çalışmaları etiketleme

Her iş isteğinin benzersiz bir tanımlayıcısı vardır. Bu tanımlayıcı, daha sonra işi iptal etmek veya ilerlemesini gözlemlemek için kullanılabilir.

Mantıksal olarak ilişkili bir iş grubunuz varsa bu iş öğelerini etiketlemek de faydalı olabilir. Etiketleme, bir grup iş isteğiyle birlikte çalışmanıza olanak tanır.

Örneğin, WorkManager.cancelAllWorkByTag(String) belirli bir etikete sahip tüm iş isteklerini iptal eder ve WorkManager.getWorkInfosByTag(String), mevcut iş durumunu belirlemek için kullanılabilecek WorkInfo nesnelerinin listesini döndürür.

Aşağıdaki kodda, çalışmanıza nasıl "temizleme" etiketi ekleyebileceğiniz gösterilmektedir:

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .addTag("cleanup")
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
       .addTag("cleanup")
       .build();

Son olarak, tek bir iş isteğine birden fazla etiket eklenebilir. Bu etiketler dahili olarak bir dize grubu şeklinde depolanır. WorkRequest ile ilişkili etiket grubunu almak için WorkInfo.getTags() kullanabilirsiniz.

Worker sınıfınızdan, ListenableWorker.getTags() kullanarak etiket grubunu alabilirsiniz.

Giriş verilerini atama

İşinizin yapılabilmesi için giriş verileri gerekebilir. Örneğin, bir resim yükleme işlemini gerçekleştiren iş, giriş olarak yüklenecek resmin URI'sini gerektirebilir.

Giriş değerleri, bir Data nesnesinde anahtar/değer çiftleri olarak depolanır ve iş isteğinde ayarlanabilir. WorkManager, çalışmayı yürütürken Data girişini çalışmanıza iletir. Worker sınıfı, Worker.getInputData() yöntemini çağırarak giriş bağımsız değişkenlerine erişebilir. Aşağıdaki kodda, giriş verileri gerektiren bir Worker örneğini nasıl oluşturabileceğiniz ve bunu iş isteğinizde nasıl göndereceğiniz gösterilmektedir.

Kotlin

// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
   : Worker(appContext, workerParams) {

   override fun doWork(): Result {
       val imageUriInput =
           inputData.getString("IMAGE_URI") ?: return Result.failure()

       uploadFile(imageUriInput)
       return Result.success()
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>()
   .setInputData(workDataOf(
       "IMAGE_URI" to "http://..."
   ))
   .build()

Java

// Define the Worker requiring input
public class UploadWork extends Worker {

   public UploadWork(Context appContext, WorkerParameters workerParams) {
       super(appContext, workerParams);
   }

   @NonNull
   @Override
   public Result doWork() {
       String imageUriInput = getInputData().getString("IMAGE_URI");
       if(imageUriInput == null) {
           return Result.failure();
       }

       uploadFile(imageUriInput);
       return Result.success();
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
      new OneTimeWorkRequest.Builder(UploadWork.class)
           .setInputData(
               new Data.Builder()
                   .putString("IMAGE_URI", "http://...")
                   .build()
           )
           .build();

Benzer şekilde, bir dönüş değeri oluşturmak için Data sınıfını kullanabilirsiniz.

Sonraki Adımlar

Durumlar ve gözlem sayfasında, çalışma durumları ve çalışmanızın ilerleme durumunu nasıl izleyeceğiniz hakkında daha fazla bilgi edineceksiniz.