Arka plan optimizasyonu

Arka plan işlemleri, bellek ve pil yoğun olabilir. Örneğin, örtülü bir yayın, çok fazla işe yaramasa bile onu dinlemek üzere kaydedilmiş birçok arka plan işlemi başlatabilir. Bunun hem cihaz performansı hem de kullanıcı deneyimi üzerinde önemli bir etkisi olabilir.

Android 7.0 (API düzeyi 24), bu sorunu hafifletmek için aşağıdaki kısıtlamaları uygular:

Uygulamanız bu amaçlardan birini kullanıyorsa Android 7.0 veya sonraki sürümleri çalıştıran cihazları düzgün bir şekilde hedefleyebilmek için bunlara olan bağımlılıkları en kısa sürede kaldırmalısınız. Android çerçevesi, bu örtülü yayınlara olan ihtiyacı azaltmak için çeşitli çözümler sunar. Örneğin JobScheduler ve yeni WorkManager, belirtilen koşullar karşılandığında (ör. sınırsız bir ağa bağlantı) ağ işlemlerinin planlanması için güçlü mekanizmalar sunar. Artık içerik sağlayıcılarda yapılan değişikliklere tepki vermek için JobScheduler kullanabilirsiniz. JobInfo nesneleri, JobScheduler ürününün işinizi planlamak için kullandığı parametreleri içerir. İş koşulları karşılandığında, sistem bu işi uygulamanızın JobService cihazında yürütür.

Bu sayfada, uygulamanızı bu yeni kısıtlamalara uyarlamak için JobScheduler gibi alternatif yöntemleri nasıl kullanacağınızı öğreneceksiniz.

Kullanıcı tarafından başlatılan kısıtlamalar

Kullanıcı, Sistem ayarlarındaki Pil kullanımı sayfasında aşağıdaki seçeneklerden birini belirleyebilir:

  • Kısıtlanmamış: Tüm arka plan çalışmalarına izin verilir. Bu durum daha fazla pil tüketebilir.
  • Optimize edilmiş (varsayılan): Bir uygulamanın, kullanıcının uygulama ile nasıl etkileşimde bulunduğuna bağlı olarak arka plan çalışması gerçekleştirme becerisini optimize edin.
  • Kısıtlı: Bir uygulamanın arka planda çalışmasını tamamen engeller. Uygulamalar beklendiği gibi çalışmayabilir.

Bir uygulama, Android vitals bölümünde açıklanan kötü davranışlardan bazılarını sergilerse sistem, kullanıcıdan uygulamanın sistem kaynaklarına erişimini kısıtlamasını isteyebilir.

Sistem, bir uygulamanın aşırı kaynak kullandığını tespit ederse kullanıcıyı bilgilendirir ve uygulamanın işlemlerini kısıtlama seçeneği sunar. Bildirimi tetikleyebilecek davranışlar arasında şunlar yer alır:

  • Aşırı sayıda uyanık kalma kilitleri: Ekran kapalıyken bir saat süreyle tutulan 1 kısmi uyanık kalma kilidi
  • Aşırı düzeyde arka plan hizmeti: Uygulama 26'nın altındaki API düzeylerini hedefliyorsa ve aşırı miktarda arka plan hizmeti içeriyorsa

Uygulanan kesin kısıtlamalar cihaz üreticisi tarafından belirlenir. Örneğin, Android 9 (API düzeyi 28) veya sonraki sürümleri çalıştıran AOSP derlemelerinde "kısıtlanmış" durumda olan arka planda çalışan uygulamalar aşağıdaki sınırlamalara sahiptir:

  • Ön plan hizmetleri başlatılamıyor
  • Mevcut ön plan hizmetleri ön plandan kaldırılır
  • Alarmlar tetiklenmedi
  • İşler yürütülmüyor

Ayrıca bir uygulama Android 13 (API düzeyi 33) veya sonraki sürümleri hedefliyorsa ve "kısıtlanmış" durumdaysa sistem, uygulama başka nedenlerle başlatılana kadar BOOT_COMPLETED yayınını veya LOCKED_BOOT_COMPLETED yayınını yayınlamaz.

İlgili kısıtlamalar Güç yönetimi kısıtlamaları başlıklı makalede listelenmiştir.

Ağ etkinliği yayınlarını almayla ilgili kısıtlamalar

Android 7.0'ı (API düzeyi 24) hedefleyen uygulamalar, bunları manifest dosyalarına almak üzere kaydolursa CONNECTIVITY_ACTION yayınlarını almaz ve bu yayına bağlı olan işlemler başlamaz. Bu durum, cihaz sınırsız bir ağa bağlandığında ağ değişikliklerini dinlemek veya toplu ağ etkinlikleri gerçekleştirmek isteyen uygulamalar için bir sorun oluşturabilir. Android çerçevesinde bu kısıtlamayı aşmayı sağlayacak birçok çözüm zaten mevcuttur, ancak doğru çözümün seçilmesi, uygulamanızın neyi başarmasını istediğinize bağlıdır.

Not: Context.registerReceiver() uygulamasına kayıtlı bir BroadcastReceiver, uygulama çalışırken bu yayınları almaya devam eder.

Sayaçsız bağlantılarda ağ işlerini planlama

JobInfo nesnenizi derlemek için JobInfo.Builder sınıfını kullanırken setRequiredNetworkType() yöntemini uygulayın ve JobInfo.NETWORK_TYPE_UNMETERED parametresini iş parametresi olarak iletin. Aşağıdaki kod örneğinde, cihaz sınırsız bir ağa bağlanıp şarj olurken bir hizmetin çalışması planlanır:

Kotlin

const val MY_BACKGROUND_JOB = 0
...
fun scheduleJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    val job = JobInfo.Builder(
            MY_BACKGROUND_JOB,
            ComponentName(context, MyJobService::class.java)
    )
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
            .setRequiresCharging(true)
            .build()
    jobScheduler.schedule(job)
}

Java

public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
  JobScheduler js =
      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
  JobInfo job = new JobInfo.Builder(
    MY_BACKGROUND_JOB,
    new ComponentName(context, MyJobService.class))
      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
      .setRequiresCharging(true)
      .build();
  js.schedule(job);
}

İşinizin koşulları karşılandığında uygulamanız, belirtilen JobService.class içinde onStartJob() yöntemini çalıştırmak için bir geri çağırma alır. JobScheduler uygulamasına ilişkin daha fazla örnek görmek için JobScheduler örnek uygulamasına bakın.

JobScheduler'ın yeni alternatifi WorkManager'dır. Bu API, uygulama sürecinin mevcut olup olmadığına bakılmaksızın garantili olarak tamamlanmasını gerektiren arka plan görevlerini planlamanıza olanak tanır. WorkManager, cihazın API düzeyi gibi faktörlere bağlı olarak işi çalıştırmak için uygun yöntemi seçer (doğrudan uygulama işleminizdeki bir iş parçacığı üzerinde ve JobScheduler, FirebaseJobDispatcher veya AlarmManager). Ayrıca WorkManager, Play Hizmetleri gerektirmez ve zincirleme görevleri birbirine bağlama veya görevlerin durumunu kontrol etme gibi çeşitli gelişmiş özellikler sunar. Daha fazla bilgi edinmek için WorkManager'a bakın.

Uygulama çalışırken ağ bağlantısını izleme

Çalışan uygulamalar kayıtlı bir BroadcastReceiver ile CONNECTIVITY_CHANGE çalmaya devam edebilir. Bununla birlikte ConnectivityManager API, yalnızca belirtilen ağ koşulları karşılandığında geri çağırma isteğinde bulunmak için daha sağlam bir yöntem sunar.

NetworkRequest nesneleri, ağ geri çağırma parametrelerini NetworkCapabilities açısından tanımlar. NetworkRequest.Builder sınıfıyla NetworkRequest nesneleri oluşturabilirsiniz. registerNetworkCallback(), daha sonra NetworkRequest nesnesini sisteme iletir. Ağ koşulları karşılandığında uygulama, ConnectivityManager.NetworkCallback sınıfında tanımlanan onAvailable() yöntemini yürütmek için bir geri çağırma alır.

Uygulama, çıkış yapana veya unregisterNetworkCallback() çağrısı yapana kadar geri çağırmaları almaya devam eder.

Görüntü ve video yayınlarını almayla ilgili kısıtlamalar

Android 7.0'da (API düzeyi 24) uygulamalar, ACTION_NEW_PICTURE veya ACTION_NEW_VIDEO yayınlarını gönderemez ya da alamaz. Bu kısıtlama, yeni bir resmi veya videoyu işlemek için bazı uygulamaların uyanması gerektiğinde performans ve kullanıcı deneyimi üzerindeki etkileri hafifletmeye yardımcı olur. Android 7.0 (API düzeyi 24), alternatif bir çözüm sunmak için JobInfo ve JobParameters sürümlerini genişletir.

İçerik URI'si değişikliklerinde işleri tetikleme

Android 7.0 (API düzeyi 24), içerik URI değişikliklerinde işleri tetiklemek için JobInfo API'yi aşağıdaki yöntemlerle genişletir:

JobInfo.TriggerContentUri()
İçerik URI'si değişikliklerinde bir iş tetiklemek için gereken parametreleri içerir.
JobInfo.Builder.addTriggerContentUri()
JobInfo öğesine bir TriggerContentUri nesnesi geçirir. ContentObserver, kapsüllenmiş içerik URI'sini izler. Bir işle ilişkilendirilmiş birden fazla TriggerContentUri nesnesi varsa sistem, yalnızca içerik URI'larından birinde değişiklik bildirse bile bir geri çağırma sağlar.
Belirtilen URI'nın herhangi bir alt öğesi değişirse işi tetiklemek için TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS işaretini ekleyin. Bu işaret, registerContentObserver() için iletilen notifyForDescendants parametresine karşılık gelir.

Not: TriggerContentUri(), setPeriodic() veya setPersisted() ile birlikte kullanılamaz. İçerik değişikliklerini sürekli olarak izlemek için uygulamanın JobService en son geri çağırma işlemini tamamlamadan önce yeni bir JobInfo planlayın.

Aşağıdaki örnek kod, sistem MEDIA_URI içerik URI'sında bir değişiklik bildirdiğinde tetiklenecek bir iş planlar:

Kotlin

const val MY_BACKGROUND_JOB = 0
...
fun scheduleJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    val job = JobInfo.Builder(
            MY_BACKGROUND_JOB,
            ComponentName(context, MediaContentJob::class.java)
    )
            .addTriggerContentUri(
                    JobInfo.TriggerContentUri(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
                    )
            )
            .build()
    jobScheduler.schedule(job)
}

Java

public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
  JobScheduler js =
          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
  JobInfo.Builder builder = new JobInfo.Builder(
          MY_BACKGROUND_JOB,
          new ComponentName(context, MediaContentJob.class));
  builder.addTriggerContentUri(
          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
  js.schedule(builder.build());
}

Sistem, belirtilen içerik URI'lerinde değişiklik bildirdiğinde uygulamanız bir geri çağırma alır ve MediaContentJob.class öğesindeki onStartJob() yöntemine JobParameters nesnesi aktarılır.

Hangi içerik yetkililerinin bir işi tetiklediğini belirleyin

Android 7.0 (API düzeyi 24), uygulamanızın işi hangi içerik yetkililerinin ve URI'lerin tetiklediği hakkında faydalı bilgiler almasını sağlamak için JobParameters kapsamını da genişletir:

Uri[] getTriggeredContentUris()
İşi tetikleyen bir URI dizisi döndürür. İşi hiçbir URI tetiklemediyse (örneğin, iş son tarih nedeniyle veya başka bir nedenden dolayı tetiklendiyse) ya da değiştirilen URI'ların sayısı 50'den fazlaysa bu değer null olur.
String[] getTriggeredContentAuthorities()
İşi tetikleyen içerik yetkililerinin dize dizisini döndürür. Döndürülen dizi null değilse hangi URI'lerin değiştiğine dair ayrıntıları almak için getTriggeredContentUris() işlevini kullanın.

Aşağıdaki örnek kod, JobService.onStartJob() yöntemini geçersiz kılar ve işi tetikleyen içerik yetkililerini ve URI'ları kaydeder:

Kotlin

override fun onStartJob(params: JobParameters): Boolean {
    StringBuilder().apply {
        append("Media content has changed:\n")
        params.triggeredContentAuthorities?.also { authorities ->
            append("Authorities: ${authorities.joinToString(", ")}\n")
            append(params.triggeredContentUris?.joinToString("\n"))
        } ?: append("(No content)")
        Log.i(TAG, toString())
    }
    return true
}

Java

@Override
public boolean onStartJob(JobParameters params) {
  StringBuilder sb = new StringBuilder();
  sb.append("Media content has changed:\n");
  if (params.getTriggeredContentAuthorities() != null) {
      sb.append("Authorities: ");
      boolean first = true;
      for (String auth :
          params.getTriggeredContentAuthorities()) {
          if (first) {
              first = false;
          } else {
             sb.append(", ");
          }
           sb.append(auth);
      }
      if (params.getTriggeredContentUris() != null) {
          for (Uri uri : params.getTriggeredContentUris()) {
              sb.append("\n");
              sb.append(uri);
          }
      }
  } else {
      sb.append("(No content)");
  }
  Log.i(TAG, sb.toString());
  return true;
}

Uygulamanızı daha da optimize edin

Uygulamalarınızı düşük bellekli cihazlarda veya düşük bellek koşullarında çalışacak şekilde optimize etmek performansı ve kullanıcı deneyimini iyileştirebilir. Arka plan hizmetlerine ve manifeste kayıtlı örtülü yayın alıcılarına olan bağımlılıkları kaldırmak, uygulamanızın bu tür cihazlarda daha iyi çalışmasına yardımcı olabilir. Android 7.0 (API düzeyi 24) bu sorunların bazılarını azaltmak için adımlar atsa da uygulamanızı bu arka plan işlemlerini tamamen kullanmadan çalışacak şekilde optimize etmeniz önerilir.

Aşağıdaki Android Debug Bridge (ADB) komutları, arka plan işlemleri devre dışıyken uygulama davranışını test etmenize yardımcı olabilir:

  • Örtülü yayınların ve arka plan hizmetlerinin kullanılamadığı koşulları simüle etmek için aşağıdaki komutu girin:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
    
  • Örtülü yayınları ve arka plan hizmetlerini yeniden etkinleştirmek için aşağıdaki komutu girin:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
    
  • Arka planda pil kullanımı için kullanıcıyı, uygulamanızı "kısıtlanmış" duruma getirmesini simüle edebilirsiniz. Bu ayar, uygulamanızın arka planda çalışmasını engeller. Bu işlemi yapmak için bir terminal penceresinde şu komutu çalıştırın:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny