Arka plan işlemleri, bellek ve pil açısından yoğun olabilir. Örneğin, örtülü bir yayın, çok fazla iş yapmayacak olsalar bile dinlemek için kaydolan birçok arka plan işlemini başlatabilir. Bu durum, hem cihaz performansı hem de kullanıcı deneyimi üzerinde önemli bir etkiye sahip olabilir.
Bu sorunu hafifletmek için Android 7.0 (API düzeyi 24) aşağıdaki kısıtlamaları uygular:
- Android 7.0 (API düzeyi 24) ve sonraki sürümleri hedefleyen uygulamalar, yayın alıcılarını manifest dosyasında tanımlamaları durumunda
CONNECTIVITY_ACTION
yayınlarını almaz. Uygulamalar,CONNECTIVITY_ACTION
ileBroadcastReceiver
kaydettirirlerse ve bu bağlam hâlâ geçerliyseContext.registerReceiver()
yayınlarını almaya devam eder. - Uygulamalar
ACTION_NEW_PICTURE
veyaACTION_NEW_VIDEO
yayınları gönderemez ya da alamaz. Bu optimizasyon, yalnızca Android 7.0'ı (API düzeyi 24) hedefleyen uygulamaları değil, tüm uygulamaları etkiler.
Uygulamanız bu amaçlardan herhangi birini kullanıyorsa Android 7.0 veya sonraki sürümleri çalıştıran cihazları düzgün bir şekilde hedefleyebilmek için en kısa sürede bunlara olan bağımlılıkları kaldırmanız gerekir. Android çerçevesi, bu örtülü yayınlara duyulan ihtiyacı azaltmak için çeşitli çözümler sunar. Örneğin, JobScheduler
ve yeni WorkManager, belirli koşullar (ör. sınırsız bir ağa bağlantı) karşılandığında ağ işlemlerini planlamak için güçlü mekanizmalar sağlar. Artık JobScheduler
kullanarak içerik sağlayıcılarda yapılan değişikliklere de tepki verebilirsiniz. JobInfo
nesneleri, JobScheduler
işinizi planlamak için kullandığı parametreleri kapsar. İşin koşulları karşılandığında sistem, bu işi uygulamanızın JobService
üzerinde 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ı öğreneceğiz.
Kullanıcı tarafından başlatılan kısıtlamalar
Kullanıcı, Sistem ayarlarındakiPil kullanımı sayfasında aşağıdaki seçeneklerden birini belirleyebilir:
- Kısıtlanmamış: Daha fazla pil tüketebilecek tüm arka plan işlemlerine izin verilir.
- Optimize edilmiş (varsayılan): Kullanıcının uygulamayla etkileşimine göre, uygulamanın arka planda çalışma yapma özelliğini optimize eder.
- Kısıtlanmış: Uygulamanın arka planda çalışmasını tamamen engeller. Uygulamalar beklendiği gibi çalışmayabilir.
Bir uygulama, Android vitals'da açıklanan kötü davranışlardan bazılarını sergiliyorsa sistem, kullanıcıdan bu uygulamanın sistem kaynaklarına erişimini kısıtlamasını isteyebilir.
Sistem, bir uygulamanın aşırı kaynak tükettiğini fark ederse kullanıcıyı bilgilendirir ve kullanıcının uygulamanın işlemlerini kısıtlamasına olanak tanır. Uyarıyı tetikleyebilecek davranışlar şunlardır:
- Aşırı sayıda uyanık kalma kilidi: Ekran kapalıyken bir saat boyunca tutulan 1 kısmi uyanık kalma kilidi
- Aşırı arka plan hizmetleri: Uygulama, 26'dan düşük API düzeylerini hedefliyorsa ve aşırı arka plan hizmetleri varsa
Uygulanan kısıtlamalar, cihaz üreticisi tarafından belirlenir. Örneğin, Android 9 (API düzeyi 28) veya sonraki sürümlerin çalıştığı AOSP derlemelerinde, arka planda çalışan ve "kısıtlanmış" durumda olan 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 tetiklenmiyor
- İşler yürütülmüyor
Ayrıca, Android 13'ü (API düzeyi 33) veya sonraki sürümleri hedefleyen ve"kısıtlanmış" durumda olan bir uygulama başka nedenlerle başlatılana kadar sistem BOOT_COMPLETED
yayınını veya LOCKED_BOOT_COMPLETED
yayınını teslim etmez.
Belirli kısıtlamalar Güç yönetimiyle ilgili kısıtlamalar bölümünde listelenmiştir.
Ağ etkinliği yayınlarını alma kısıtlamaları
Android 7.0'ı (API düzeyi 24) hedefleyen uygulamalar, manifest dosyalarında CONNECTIVITY_ACTION
yayınlarını alacak şekilde kaydolmuş olsalar bile bu yayınları almaz ve bu yayına bağlı olan işlemler başlatılmaz. 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 sorun oluşturabilir. Bu kısıtlamayı aşmak için Android çerçevesinde halihazırda çeşitli çözümler bulunmaktadır. Ancak doğru çözümü seçmek, uygulamanızın ne yapmasını istediğinize bağlıdır.
Not: BroadcastReceiver
ile kaydedilen bir
Context.registerReceiver()
uygulama çalışırken bu yayınları almaya devam eder.
Ölçülmeyen bağlantılarda ağ işlerini planlama
JobInfo.Builder
sınıfını kullanarak JobInfo
nesnenizi oluştururken setRequiredNetworkType()
yöntemini uygulayın ve JobInfo.NETWORK_TYPE_UNMETERED
öğesini iş parametresi olarak iletin. Aşağıdaki kod örneği, cihaz sınırsız bir ağa bağlandığında ve şarj olurken çalışacak bir hizmet 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, 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); }
İşinizle ilgili koşullar karşılandığında uygulamanız, belirtilen JobService.class
içinde onStartJob()
yöntemini çalıştırmak için geri çağırma alır. JobScheduler
uygulamasının daha fazla örneğini görmek için JobScheduler örnek uygulamasına bakın.
JobScheduler'a yeni bir alternatif olarak WorkManager'ı kullanabilirsiniz. Bu API, uygulama süreci çalışıyor olsun veya olmasın, tamamlanması garanti edilmesi gereken arka plan görevlerini planlamanıza olanak tanır. WorkManager, işi çalıştırmak için uygun yöntemi (JobScheduler, FirebaseJobDispatcher veya AlarmManager'ı kullanmanın yanı sıra doğrudan uygulamanızın işlemindeki bir iş parçacığında) cihazın API düzeyi gibi faktörlere göre seçer. Ayrıca WorkManager, Play Hizmetleri'ni gerektirmez ve görevleri birbirine bağlama veya görev durumunu kontrol etme gibi çeşitli gelişmiş özellikler sunar. Daha fazla bilgi için WorkManager başlıklı makaleyi inceleyin.
Uygulama çalışırken ağ bağlantısını izleme
Çalışan uygulamalar, kayıtlı bir BroadcastReceiver
ile CONNECTIVITY_CHANGE
için dinlemeye devam edebilir. Ancak ConnectivityManager
API, yalnızca belirtilen ağ koşulları karşılandığında geri arama isteğinde bulunmak için daha güçlü bir yöntem sağlar.
NetworkRequest
nesneleri, NetworkCapabilities
açısından ağ geri aramasının parametrelerini tanımlar. NetworkRequest.Builder
sınıfıyla NetworkRequest
nesne oluşturursunuz. registerNetworkCallback()
ve NetworkRequest
nesnesini sisteme iletir. Ağ koşulları karşılandığında uygulama, onAvailable()
sınıfında tanımlanan ConnectivityManager.NetworkCallback
yöntemini yürütmek için geri çağırma alır.
Uygulama çıkana veya unregisterNetworkCallback()
çağrılana kadar geri çağırmalar almaya devam eder.
Resim ve video yayınları alma ile ilgili kısıtlamalar
Android 7.0'da (API düzeyi 24) uygulamalar ACTION_NEW_PICTURE
veya ACTION_NEW_VIDEO
yayınları gönderemez ya da alamaz. Bu kısıtlama, yeni bir resim veya videonun işlenmesi için birden fazla uygulamanın uyandırılması gerektiğinde performans ve kullanıcı deneyimi üzerindeki etkileri azaltmaya yardımcı olur. Android 7.0 (API düzeyi 24), alternatif bir çözüm sunmak için JobInfo
ve JobParameters
'yi genişletir.
İçerik URI'si değişikliklerinde işleri tetikleme
Android 7.0 (API düzeyi 24), içerik URI'si değişikliklerinde işleri tetiklemek için JobInfo
API'sini aşağıdaki yöntemlerle genişletir:
-
JobInfo.TriggerContentUri()
- İçerik URI'si değişikliklerinde bir işi tetiklemek için gereken parametreleri kapsar.
-
JobInfo.Builder.addTriggerContentUri()
-
TriggerContentUri
nesnesiniJobInfo
'ye iletir. BirContentObserver
kapsüllenmiş içerik URI'sini izler. Bir işle ilişkilendirilmiş birden fazlaTriggerContentUri
nesnesi varsa sistem, yalnızca içerik URI'lerinden birinde değişiklik bildirse bile geri çağırma sağlar. -
Belirtilen URI'nin alt öğelerinden herhangi biri değişirse işi tetiklemek için
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
işaretini ekleyin. Bu işaret,notifyForDescendants
parametresininregisterContentObserver()
'ye iletilmesine 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 JobInfo
en son geri çağırmayı işlemesi bitmeden yeni bir JobService
planlayın.
Aşağıdaki örnek kod, sistem içerik URI'sinde değişiklik olduğunu bildirdiğinde tetiklenecek bir iş planlar, MEDIA_URI
:
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 bir değişiklik olduğunu bildirdiğinde uygulamanız geri çağırma alır ve JobParameters
nesnesi MediaContentJob.class
içindeki onStartJob()
yöntemine iletilir.
Hangi içerik yetkililerinin bir işi tetiklediğini belirleme
Android 7.0 (API düzeyi 24), JobParameters
işlevini genişleterek uygulamanızın, hangi içerik yetkililerinin ve URI'lerin işi tetiklediği hakkında faydalı bilgiler almasına olanak tanır:
-
Uri[] getTriggeredContentUris()
-
İşi tetikleyen URI dizisini döndürür. Bu değer, URI'lerden hiçbiri işi tetiklemediyse (örneğin, iş bir son tarih veya başka bir nedenle tetiklendiyse) ya da değiştirilen URI sayısı 50'den fazlaysa
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ğiyle ilgili ayrıntıları almak içingetTriggeredContentUris()
kullanın.
Aşağıdaki örnek kod, JobService.onStartJob()
yöntemini geçersiz kılar ve işi tetikleyen içerik yetkililerini ve URI'leri 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 etme
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 manifestte 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 seviyesi 24) bu sorunlardan bazılarını azaltmak için adımlar atsa da uygulamanızı bu arka plan işlemlerini hiç kullanmadan çalışacak şekilde optimize etmeniz önerilir.
Aşağıdaki Android Debug Bridge (ADB) komutları, arka plan işlemleri devre dışı bırakılmışken 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 şu 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
- Kullanıcının, uygulamanızı arka planda pil kullanımı için "kısıtlanmış" duruma getirmesini simüle edebilirsiniz. Bu ayar, uygulamanızın arka planda çalışmasını engeller. Bunu yapmak 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