Uygulamanızın ağa yaptığı istekler, güç tüketen hücresel veya kablosuz radyoları açtığı için pilin boşalmasının önemli bir nedenidir. Bu radyolar, paket göndermek ve almak için gereken gücün yanı sıra yalnızca açılıp uyanık kalmak için de ekstra güç harcar. 15 saniyede bir yapılan ağ isteği gibi basit bir işlem bile mobil radyoyu sürekli açık tutarak pil gücünün hızlıca tükenmesine neden olabilir.
Üç genel düzenli güncelleme türü vardır:
- Kullanıcı tarafından başlatılan Yenilemek için çekme hareketi gibi bazı kullanıcı davranışlarına göre güncelleme yapma.
- Uygulama tarafından başlatılır. Düzenli olarak güncelleme yapma
- Sunucu tarafından başlatılır. Bir sunucudan gelen bildirime yanıt olarak güncelleme yapma.
Bu konuda, bunların her biri ele alınmakta ve pil tüketimini azaltmak için optimize edilebilecek ek yöntemler tartışılmaktadır.
Kullanıcı tarafından başlatılan istekleri optimize etme
Kullanıcı tarafından başlatılan istekler genellikle bir kullanıcı davranışına yanıt olarak gerçekleşir. Örneğin, en son haber makalelerini okumak için kullanılan bir uygulama, kullanıcının yeni makaleleri kontrol etmek için aşağı çekerek yenileme hareketi yapmasına izin verebilir. Ağ kullanımını optimize ederken kullanıcı tarafından başlatılan isteklere yanıt vermek için aşağıdaki teknikleri kullanabilirsiniz.
Kullanıcı isteklerini sınırlama
Gerekli olmayan kullanıcı tarafından başlatılan istekleri (ör. mevcut veriler henüz güncelken yeni verileri kontrol etmek için kısa süre içinde birden fazla kez yenilemek üzere çekme hareketi yapılması) göz ardı edebilirsiniz. Her isteğe yanıt vermek, radyoyu uyanık tutarak önemli miktarda güç kaybına neden olabilir. Daha verimli bir yaklaşım, kullanıcı tarafından başlatılan istekleri sınırlayarak belirli bir süre içinde yalnızca bir istekte bulunulmasını sağlamaktır. Bu sayede radyonun kullanım sıklığı azaltılır.
Önbelleği kullanma
Uygulamanızın verilerini önbelleğe alarak, uygulamanızın referans vermesi gereken bilgilerin yerel bir kopyasını oluşturursunuz. Uygulamanız daha sonra yeni isteklerde bulunmak için bir ağ bağlantısı açmak zorunda kalmadan bilgilerin aynı yerel kopyasına birden çok kez erişebilir.
Statik kaynaklar ve tam boyutlu resimler gibi isteğe bağlı indirmeler de dahil olmak üzere verileri mümkün olduğunca agresif bir şekilde önbelleğe almalısınız. Önbelleğe alma stratejinizin, uygulamanızın eski veriler göstermesine neden olmamasını sağlamak için HTTP önbellek üstbilgilerini kullanabilirsiniz. Ağ yanıtlarını önbelleğe alma hakkında daha fazla bilgi için Gereksiz indirmelerden kaçınma başlıklı makaleyi inceleyin.
Android 11 ve sonraki sürümlerde uygulamanız, diğer uygulamaların makine öğrenimi ve medya oynatma gibi kullanım alanlarında kullandığı büyük veri kümelerini kullanabilir. Uygulamanızın paylaşılan bir veri kümesine erişmesi gerektiğinde yeni bir kopya indirmeye çalışmadan önce önbelleğe alınmış bir sürüm olup olmadığını kontrol edebilir. Paylaşılan veri kümeleri hakkında daha fazla bilgi edinmek için Paylaşılan veri kümelerine erişme başlıklı makaleyi inceleyin.
Daha fazla veri indirmek için daha yüksek bant genişliği kullanma
Kablosuz radyo üzerinden bağlantı kurulduğunda daha yüksek bant genişliği genellikle daha yüksek pil maliyetiyle birlikte gelir. Bu da 5G'nin genellikle LTE'den daha fazla enerji tükettiği, LTE'nin ise 3G'den daha fazla enerji tükettiği anlamına gelir.
Bu, temel radyo durumu radyo teknolojisine göre değişse de genel olarak durum değişikliği kuyruk süresinin göreceli pil etkisinin daha yüksek bant genişliğine sahip radyolarda daha fazla olduğu anlamına gelir. Kuyruk süresi hakkında daha fazla bilgi için Radyo durum makinesi başlıklı makaleye bakın.
Aynı zamanda, daha yüksek bant genişliği sayesinde daha fazla veriyi aynı süre içinde indirerek daha agresif bir şekilde önceden getirebilirsiniz. Belki de daha az sezgisel olarak, kuyruk süresi pil maliyeti nispeten daha yüksek olduğundan, güncellemelerin sıklığını azaltmak için her aktarım oturumu sırasında radyoyu daha uzun süre etkin tutmak da daha verimlidir.
Örneğin, bir LTE radyonun bant genişliği ve enerji maliyeti 3G'nin iki katıysa her oturumda dört kat daha fazla veri (10 MB'a kadar) indirmeniz gerekir. Bu kadar çok veri indirirken, önceden getirme işleminizin kullanılabilir yerel depolama alanı üzerindeki etkisini göz önünde bulundurmanız ve önceden getirme önbelleğinizi düzenli olarak temizlemeniz önemlidir.
Varsayılan ağ için bir dinleyici kaydetmek üzere ConnectivityManager
, mevcut cihaz bağlantı türünü belirlemek üzere PhoneStateListener
kaydetmek için TelephonyManager
kullanabilirsiniz. Bağlantı türü bilindikten sonra,
önceden getirme rutinlerinizi buna göre değiştirebilirsiniz:
Kotlin
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager private var hasWifi = false private var hasCellular = false private var cellModifier: Float = 1f private val networkCallback = object : ConnectivityManager.NetworkCallback() { // Network capabilities have changed for the network override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) hasCellular = networkCapabilities .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) hasWifi = networkCapabilities .hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } } private val phoneStateListener = object : PhoneStateListener() { override fun onPreciseDataConnectionStateChanged( dataConnectionState: PreciseDataConnectionState ) { cellModifier = when (dataConnectionState.networkType) { TelephonyManager.NETWORK_TYPE_LTE or TelephonyManager.NETWORK_TYPE_HSPAP -> 4f TelephonyManager.NETWORK_TYPE_EDGE or TelephonyManager.NETWORK_TYPE_GPRS -> 1/2f else -> 1f } } private class NetworkState { private var defaultNetwork: Network? = null private var defaultCapabilities: NetworkCapabilities? = null fun setDefaultNetwork(network: Network?, caps: NetworkCapabilities?) = synchronized(this) { defaultNetwork = network defaultCapabilities = caps } val isDefaultNetworkWifi get() = synchronized(this) { defaultCapabilities?.hasTransport(TRANSPORT_WIFI) ?: false } val isDefaultNetworkCellular get() = synchronized(this) { defaultCapabilities?.hasTransport(TRANSPORT_CELLULAR) ?: false } val isDefaultNetworkUnmetered get() = synchronized(this) { defaultCapabilities?.hasCapability(NET_CAPABILITY_NOT_METERED) ?: false } var cellNetworkType: Int = TelephonyManager.NETWORK_TYPE_UNKNOWN get() = synchronized(this) { field } set(t) = synchronized(this) { field = t } private val cellModifier: Float get() = synchronized(this) { when (cellNetworkType) { TelephonyManager.NETWORK_TYPE_LTE or TelephonyManager.NETWORK_TYPE_HSPAP -> 4f TelephonyManager.NETWORK_TYPE_EDGE or TelephonyManager.NETWORK_TYPE_GPRS -> 1 / 2f else -> 1f } } val prefetchCacheSize: Int get() = when { isDefaultNetworkWifi -> MAX_PREFETCH_CACHE isDefaultNetworkCellular -> (DEFAULT_PREFETCH_CACHE * cellModifier).toInt() else -> DEFAULT_PREFETCH_CACHE } } private val networkState = NetworkState() private val networkCallback = object : ConnectivityManager.NetworkCallback() { // Network capabilities have changed for the network override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { networkState.setDefaultNetwork(network, networkCapabilities) } override fun onLost(network: Network?) { networkState.setDefaultNetwork(null, null) } } private val telephonyCallback = object : TelephonyCallback(), TelephonyCallback.PreciseDataConnectionStateListener { override fun onPreciseDataConnectionStateChanged(dataConnectionState: PreciseDataConnectionState) { networkState.cellNetworkType = dataConnectionState.networkType } } connectivityManager.registerDefaultNetworkCallback(networkCallback) telephonyManager.registerTelephonyCallback(telephonyCallback) private val prefetchCacheSize: Int get() { return when { hasWifi -> MAX_PREFETCH_CACHE hasCellular -> (DEFAULT_PREFETCH_CACHE * cellModifier).toInt() else -> DEFAULT_PREFETCH_CACHE } } }
Java
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); private boolean hasWifi = false; private boolean hasCellular = false; private float cellModifier = 1f; private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities); hasCellular = networkCapabilities .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); hasWifi = networkCapabilities .hasTransport(NetworkCapabilities.TRANSPORT_WIFI); } }; private PhoneStateListener phoneStateListener = new PhoneStateListener() { @Override public void onPreciseDataConnectionStateChanged( @NonNull PreciseDataConnectionState dataConnectionState ) { switch (dataConnectionState.getNetworkType()) { case (TelephonyManager.NETWORK_TYPE_LTE | TelephonyManager.NETWORK_TYPE_HSPAP): cellModifier = 4; Break; case (TelephonyManager.NETWORK_TYPE_EDGE | TelephonyManager.NETWORK_TYPE_GPRS): cellModifier = 1/2.0f; Break; default: cellModifier = 1; Break; } } }; cm.registerDefaultNetworkCallback(networkCallback); tm.listen( phoneStateListener, PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE ); public int getPrefetchCacheSize() { if (hasWifi) { return MAX_PREFETCH_SIZE; } if (hasCellular) { return (int) (DEFAULT_PREFETCH_SIZE * cellModifier); } return DEFAULT_PREFETCH_SIZE; }
Uygulama tarafından başlatılan istekleri optimize etme
Uygulama tarafından başlatılan istekler genellikle bir programa göre gerçekleşir. Örneğin, arka uç hizmetine günlükler veya analizler gönderen bir uygulama bu tür istekler gönderir. Uygulama tarafından başlatılan isteklerle uğraşırken bu isteklerin önceliğini, birlikte gruplandırılıp gruplandırılamayacağını ve cihaz şarj olana veya sınırsız bir ağa bağlanana kadar ertelenip ertelenemeyeceğini göz önünde bulundurun. Bu istekler dikkatli bir şekilde planlanarak ve WorkManager gibi kitaplıklar kullanılarak optimize edilebilir.
Toplu ağ istekleri
Mobil cihazlarda radyonun açılması, bağlantı kurulması ve radyonun açık tutulması için çok fazla güç gerekir. Bu nedenle, isteklerin rastgele zamanlarda işlenmesi önemli ölçüde güç tüketebilir ve pil ömrünü kısaltabilir. Daha verimli bir yaklaşım, bir dizi ağ isteğini sıraya alıp birlikte işlemektir. Bu sayede sistem, radyoyu açmanın güç maliyetini yalnızca bir kez öder ve yine de bir uygulama tarafından istenen tüm verileri alır.
WorkManager'ı kullanma
Ağ kullanılabilirliği ve güç durumu gibi belirli koşulların karşılanıp karşılanmadığını dikkate alan verimli bir programda çalışmak için WorkManager
kitaplığını kullanabilirsiniz. Örneğin, en son haber başlıklarını alan bir Worker
alt sınıfınız olduğunu varsayalım.DownloadHeadlinesWorker
Bu çalışan, cihazın sınırsız bir ağa bağlı olması ve pilinin düşük olmaması koşuluyla her saat çalışacak şekilde planlanabilir. Verileri alma konusunda sorun yaşanırsa aşağıda gösterildiği gibi özel bir yeniden deneme stratejisi uygulanır:
Kotlin
val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresBatteryNotLow(true) .build() val request = PeriodicWorkRequestBuilder<DownloadHeadlinesWorker>(1, TimeUnit.HOURS) .setConstraints(constraints) .setBackoffCriteria(BackoffPolicy.LINEAR, 1L, TimeUnit.MINUTES) .build() WorkManager.getInstance(context).enqueue(request)
Java
Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresBatteryNotLow(true) .build(); WorkRequest request = new PeriodicWorkRequest.Builder(DownloadHeadlinesWorker.class, 1, TimeUnit.HOURS) .setBackoffCriteria(BackoffPolicy.LINEAR, 1L, TimeUnit.MINUTES) .build(); WorkManager.getInstance(this).enqueue(request);
Android platformu, WorkManager'ın yanı sıra ağ görevlerini (ör. yoklama) tamamlamak için verimli bir program oluşturmanıza yardımcı olacak çeşitli araçlar da sunar. Bu araçları kullanma hakkında daha fazla bilgi edinmek için Arka plan işleme kılavuzuna bakın.
Sunucu tarafından başlatılan istekleri optimize etme
Sunucu tarafından başlatılan istekler genellikle sunucudan gelen bir bildirime yanıt olarak gerçekleşir. Örneğin, en son haber makalelerini okumak için kullanılan bir uygulama, kullanıcının kişiselleştirme tercihlerine uygun yeni bir makale grubu hakkında bildirim alabilir ve bu makaleleri indirebilir.
Firebase Cloud Messaging ile sunucu güncellemeleri gönderme
Firebase Cloud Messaging (FCM), verileri bir sunucudan belirli bir uygulama örneğine iletmek için kullanılan basit bir mekanizmadır. FCM'yi kullanarak sunucunuz, belirli bir cihazda çalışan uygulamanızı yeni veriler olduğu konusunda bilgilendirebilir.
Uygulamanızın yeni verileri sorgulamak için sunucuya düzenli olarak ping göndermesi gereken yoklamanın aksine, bu etkinliğe dayalı model, uygulamanızın yalnızca indirilecek veri olduğunu bildiğinde yeni bir bağlantı oluşturmasına olanak tanır. Model, gereksiz bağlantıları en aza indirir ve uygulamanızdaki bilgileri güncellerken gecikmeyi azaltır.
FCM, kalıcı bir TCP/IP bağlantısı kullanılarak uygulanır. Bu, kalıcı bağlantı sayısını en aza indirir ve platformun bant genişliğini optimize etmesine ve pil ömrü üzerindeki etkisini en aza indirmesine olanak tanır.