Arka plan optimizasyonu

Arka plan işlemleri bellek ve pili yoğun olarak kullanıyor olabilir. Örneğin, dolaylı bir yayın, dinlemek için kaydedilmiş birçok arka plan işlemini başlatabilir (bu işlemler pek işe yaramasa bile). Bu değişiklik hem cihaz performansını hem de kullanıcı deneyimini önemli ölçüde etkileyebilir.

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

Uygulamanız bu amaçlardan herhangi birini kullanıyorsa Android 7.0 veya sonraki sürümleri çalıştıran cihazları doğru şekilde hedefleyebilmek için bu bağımlılıkları en kısa sürede kaldırmalısınız. Android çerçevesi, bu dolaylı yayınlara duyulan ihtiyacı azaltmak için çeşitli çözümler sunar. Örneğin, JobScheduler ve yeni WorkManager, sınırsız bir ağa bağlantı gibi belirtilen koşullar karşılandığında ağ işlemlerini planlamak için sağlam mekanizmalar sağlar. Artık içerik sağlayıcılardaki değişikliklere tepki vermek için JobScheduler aracını da kullanabilirsiniz. JobInfo nesneleri, JobScheduler hizmetinin işlerinizi planlamak için kullandığı parametreleri içerir. İş koşulları karşılandığında sistem, bu işi uygulamanızın JobService bölümünde çalıştırı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ış: Daha fazla pil harcayabilecek tüm arka plan çalışmalarına izin verilir.
  • Optimize edilmiş (varsayılan): Kullanıcının uygulamayla nasıl etkileşimde bulunduğuna bağlı olarak bir uygulamanın arka plan çalışması gerçekleştirme becerisini optimize edin.
  • Kısıtlanmış: 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 bazı kötü davranışlar sergiliyorsa sistem, kullanıcıdan ilgili uygulamanın sistem kaynaklarına erişimini kısıtlamasını isteyebilir.

Sistem bir uygulamanın çok fazla kaynak tükettiğini fark ederse kullanıcıyı bilgilendirir ve kullanıcıya uygulamanın işlemlerini kısıtlama seçeneği sunar. Bildirimi tetikleyebilecek davranışlar şunlardır:

  • Aşırı sayıda uyanık kalma kilidi: Ekran kapalıyken bir saat süreyle 1 kısmi uyanık kalma kilidi tutulur
  • Aşırı arka plan hizmetleri: Uygulama 26'dan düşük API düzeylerini hedefliyorsa ve aşırı arka plan hizmetleri içeriyorsa

Uygulanan tam 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, arka planda "kısıtlı" durumunda çalışan uygulamalar aşağıdaki sınırlamalara tabidir:

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

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

Belirli kısıtlamalar, Güç yönetimi kısıtlamaları bölümünde listelenir.

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

Android 7.0'ı (API düzeyi 24) hedefleyen uygulamalar, manifestlerinde almak için kaydolurlarsa CONNECTIVITY_ACTION yayınları almazlar ve bu yayına bağlı işlemler başlamaz. Bu, 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. Bu kısıtlamayı aşmaya yönelik çeşitli çözümler Android çerçevesinde zaten mevcuttur ancak doğru olanı seçmek uygulamanızın ne başarmasını istediğinize bağlıdır.

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

Sınırsız bağlantılarda ağ işleri planlama

JobInfo nesnenizi oluşturmak için JobInfo.Builder sınıfını kullanırken setRequiredNetworkType() yöntemini uygulayın ve JobInfo.NETWORK_TYPE_UNMETERED değerini bir iş parametresi olarak iletin. Aşağıdaki kod örneği, cihaz sınırsız bir ağa bağlanıp şarj olurken çalışacak şekilde bir plan yapar:

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 arama alır. JobScheduler uygulamasının diğer örneklerini görmek için Job Scheduler örnek uygulamasına bakın.

JobPlanr'ın yeni bir alternatifi olan WorkManager, uygulama işleminin etkin olup olmamasına bakılmaksızın, tamamlanması gereken garantili görevleri arka planda planlamanıza olanak tanıyan bir API'dir. WorkManager, cihaz API düzeyi gibi faktörlere göre işi (doğrudan uygulama sürecinizdeki bir mesaj dizisinde veya JobPlanr, FirebaseJobDispatcher veya AlarmManager'ı kullanarak) çalıştırmak için uygun yöntemi seçer. Ayrıca WorkManager, Play hizmetlerini zorunlu kılmaz ve görevleri birbirine bağlama veya görevin durumunu kontrol etme gibi çeşitli gelişmiş özellikler sunar. Daha fazla bilgi edinmek için WorkManager konusuna bakın.

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

Çalışmakta olan uygulamalar, kayıtlı BroadcastReceiver cihazıyla CONNECTIVITY_CHANGE bilgisini dinlemeye devam edebilir. Ancak ConnectivityManager API, yalnızca belirtilen ağ koşulları karşılandığında geri çağırma isteğinde bulunmak için daha güçlü bir yöntem sağlar.

NetworkRequest nesneleri, ağ geri çağırma parametrelerini NetworkCapabilities açısından tanımlar. NetworkRequest.Builder sınıfıyla NetworkRequest nesne oluşturursunuz. 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 uygulamak için bir geri çağırma alır.

Uygulama, çıkış yapıncaya veya unregisterNetworkCallback() işlevini çağırana kadar geri çağırma almaya devam eder.

Resim ve video yayını almayla ilgili kısıtlamalar

Android 7.0 (API düzeyi 24) sürümünde uygulamalar ACTION_NEW_PICTURE veya ACTION_NEW_VIDEO yayınları gönderip alamaz. Bu kısıtlama, yeni bir resim veya videonun işlenmesi için birkaç uygulamanın uyanması gerektiğinde performansın ve kullanıcı deneyiminin etkilerini azaltmaya yardımcı olur. Android 7.0 (API düzeyi 24), alternatif bir çözüm sağlamak için JobInfo ve JobParameters özelliklerini kapsar.

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

Android 7.0 (API düzeyi 24), içerik URI değişikliklerindeki işleri tetiklemek için aşağıdaki yöntemleri kullanarak JobInfo API'nin kapsamını genişletir:

JobInfo.TriggerContentUri()
İçerik URI değişikliklerinde iş tetiklemek için gereken parametreleri içerir.
JobInfo.Builder.addTriggerContentUri()
JobInfo öğesine bir TriggerContentUri nesnesi geçirir. ContentObserver, kapsüllenmiş içerik URI'sını izler. Bir işle ilişkili birden fazla TriggerContentUri nesnesi varsa sistem, içerik URI'lerinden yalnızca birindeki değişikliği bildirse bile bir geri çağırma sağlar.
Belirli bir URI'nin alt öğeleri değişirse işi tetiklemek için TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS işaretini ekleyin. Bu işaret, registerContentObserver() parametresine iletilen notifyForDescendants parametresine karşılık gelir.

Not: TriggerContentUri(), setPeriodic() veya setPersisted() ile birlikte kullanılamaz. İçerik değişikliklerini devamlı olarak izlemek amacıyla, uygulamanın JobService uygulaması en son geri çağırmanın işlenmesini tamamlamadan önce yeni bir JobInfo programlayın.

Aşağıdaki örnek kod, sistem içerik URI'sinde (MEDIA_URI) 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'larındaki bir değişikliği bildirdiğinde, uygulamanız bir geri çağırma alır ve MediaContentJob.class içindeki onStartJob() yöntemine bir JobParameters nesnesi iletilir.

İşi hangi içerik yetkililerinin tetiklediğini belirleme

Ayrıca Android 7.0 (API düzeyi 24), uygulamanızın işi hangi içerik yetkilileri ve URI'ler tetiklediği hakkında faydalı bilgiler almasına izin vermek için JobParameters kapsamını genişletir:

Uri[] getTriggeredContentUris()
İşi tetikleyen bir URI dizisini döndürür. İşi tetikleyen herhangi bir URI yoksa (ör. iş, son tarih nedeniyle veya başka bir nedenle tetiklendiyse) ya da değiştirilen URI sayısı 50'den fazlaysa bu değer null olur.
String[] getTriggeredContentAuthorities()
İşi tetikleyen içerik yetkililerinden oluşan bir 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() 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ı dolaylı 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 gerekli adımları atsa da, uygulamanızı bu arka plan işlemlerini hiç kullanmadan çalışacak şekilde optimize etmeniz önerilir.

Aşağıdaki Android Hata Ayıklama Köprüsü (ADB) komutları, arka plan işlemleri devre dışıyken uygulama davranışını test etmenize yardımcı olabilir:

  • Dolaylı 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
    
  • Dolaylı 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 plan pil kullanımı için kullanıcının uygulamanızı "kısıtlı" duruma getirerek simülasyonunu yapabilirsiniz. Bu ayar, uygulamanızın arka planda çalışmasını engeller. Bunun için bir terminal penceresinde aşağıdaki komutu çalıştırın:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny