Arka plan işlemleri bellek ve pil yoğun olabilir. Örneğin, örtülü bir yayın, çok fazla iş yapmasalar bile bu yayını dinlemek için kayıtlı olan birçok arka plan işlemini başlatabilir. Bu durum hem cihaz performansını hem de kullanıcı deneyimini önemli ölçüde etkileyebilir.
Bu sorunu azaltmak için Android 7.0 (API düzeyi 24) aşağıdaki kısıtlamaları uygular:
- Android 7.0 (API seviyesi 24) ve sonraki sürümleri hedefleyen uygulamalar, yayın alıcılarını manifest dosyasında bildirirlerse
CONNECTIVITY_ACTION
yayınları almaz. Uygulamalar,BroadcastReceiver
'leriniContext.registerReceiver()
'ye kaydettirdikleri ve bu bağlamın hâlâ geçerli olduğu durumlardaCONNECTIVITY_ACTION
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 intent'lerden herhangi birini kullanıyorsa Android 7.0 veya sonraki sürümleri çalıştıran cihazları düzgün bir şekilde hedefleyebilmek için bu intent'lere olan bağımlılıkları en kısa sürede kaldırmanız gerekir. Android çerçevesi, bu dolaylı yayınlara olan ihtiyacı azaltmak için çeşitli çözümler sunar. Örneğin, JobScheduler
ve yeni WorkManager, sınırsız ağa bağlantı gibi belirli koşullar karşılandığında ağ işlemlerini planlamak için güçlü mekanizmalar sağlar. Artık içerik sağlayıcılardaki değişikliklere tepki vermek için JobScheduler
özelliğini de kullanabilirsiniz. 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ı öğ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 tüketebilecek tüm arka plan işlemlerine izin verilir.
- Optimize (varsayılan): Kullanıcının uygulamayla nasıl etkileşime geçtiğine bağlı olarak uygulamanın arka planda çalışma ö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ı sergilerse sistem, kullanıcıdan söz konusu 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 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 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ın tam olarak ne olduğu 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 çalışan ve "kısıtlanmış" durumdaki 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, 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.
Belirli kısıtlamalar Güç yönetimi kısıtlamaları bölümünde listelenmiştir.
Ağ etkinliği yayınlarını almayla ilgili kısıtlamalar
Android 7.0'ı (API düzeyi 24) hedefleyen uygulamalar, manifest dosyalarında CONNECTIVITY_ACTION
yayınları almak için kaydolursa bu yayınları almaz ve bu yayına bağlı süreçler 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 sorun oluşturabilir. Android çerçevesinde bu kısıtlamayı aşmak için halihazırda çeşitli çözümler mevcuttur. Ancak doğru çözümü seçmek, uygulamanızın neyi başarmasını istediğinize bağlıdır.
Not: Context.registerReceiver()
ile kayıtlı bir BroadcastReceiver
, uygulama çalışırken bu yayınları almaya devam eder.
Sınırsız bağlantılarda ağ işlerini 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
'ı iş parametresi olarak iletin. Aşağıdaki kod örneği, cihaz sınırsız bir ağa bağlandığında ve şarj olurken bir hizmeti çalıştıracak şekilde 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); }
İşinizin 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
uygulama örneğini görmek için JobScheduler örnek uygulamasına göz atın.
JobScheduler'a yeni bir alternatif olan WorkManager, uygulama sürecinin mevcut olup olmadığına bakılmaksızın tamamlanması gereken arka plan görevlerini planlamanıza olanak tanıyan bir API'dir. WorkManager, işi çalıştırmanın uygun yolunu (doğrudan uygulama işleminizdeki bir iş parçacığında ve JobScheduler, FirebaseJobDispatcher veya AlarmManager'ı kullanarak) cihaz API düzeyi gibi faktörlere göre seçer. Ayrıca WorkManager, Play Hizmetleri'ni gerektirmez ve görevleri birbirine zincirleme veya bir görevin 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
'yi dinlemeye devam edebilir. Ancak ConnectivityManager
API, yalnızca belirtilen ağ koşulları karşılandığında geri arama isteğinde bulunmak için daha sağlam bir yöntem sağlar.
NetworkRequest
nesneleri, ağ geri çağırma işlevinin parametrelerini NetworkCapabilities
açısından tanımlar. NetworkRequest.Builder
sınıfıyla NetworkRequest
nesnesi 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 yürütmek için geri çağırma alır.
Uygulama, uygulamadan çıkılana veya unregisterNetworkCallback()
çağrılana kadar geri çağırma almaya devam eder.
Resim ve video yayınları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 videoyu işlemek için birkaç uygulamanın uyanık kalması gerektiğinde performans ve kullanıcı deneyimi üzerindeki etkileri azaltmaya yardımcı olur. Android 7.0 (API seviyesi 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'yi 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.ContentObserver
kapsüllenen içerik URI'sini izler. Bir işle ilişkili birden fazlaTriggerContentUri
nesnesi varsa sistem, içerik URI'lerinden yalnızca birinde değişiklik bildirse bile geri çağırma sağlar. -
Belirtilen URI'nin herhangi bir alt öğesi değişirse işi tetiklemek için
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
işaretini ekleyin. Bu işaret,registerContentObserver()
parametresine iletilennotifyForDescendants
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 aramayı işlemeyi bitirmeden önce yeni bir JobInfo
planlayın.
Aşağıdaki örnek kod, sistem MEDIA_URI
içerik URI'sinde 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 bir değişiklik bildirdiğinde uygulamanıza geri çağırma çağrısı gönderilir ve MediaContentJob.class
içindeki onStartJob()
yöntemine bir JobParameters
nesnesi iletilir.
Hangi içerik yetkililerinin bir işi tetiklediğini belirleme
Android 7.0 (API düzeyi 24), JobParameters
'ü genişleterek uygulamanızın hangi içerik yetkililerinin ve URI'lerin işi tetiklediğiyle ilgili yararlı bilgiler almasına olanak tanır:
-
Uri[] getTriggeredContentUris()
-
İşi tetikleyen URI dizisini döndürür. İşi hiçbir URI tetiklemediyse (örneğin, iş bir son tarih veya başka bir nedenden dolayı tetiklendiyse) ya da değiştirilen URI 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çingetTriggeredContentUris()
'u 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 bellek kapasitesine sahip cihazlarda veya düşük bellek koşullarında çalışacak şekilde optimize etmek performansı ve kullanıcı deneyimini iyileştirebilir. Arka plan hizmetlerine ve manifest'te kayıtlı, gizli yayın alıcılarına olan bağımlılıkları kaldırmak, uygulamanızın bu tür cihazlarda daha iyi çalışmasını sağlayabilir. Android 7.0 (API seviyesi 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ük 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ük 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