Uygulamanızın ağa gönderdiği istekler, güç tüketen hücresel veya kablosuz radyoları açtığı için pilin çabuk bitmesinin önemli bir nedenidir. Bu radyolar paket gönderip almak için gereken gücün yanı sıra yalnızca açılıp uyanık kalırken ekstra güç harcar. Her 15 saniyede bir ağ isteği gibi basit bir işlem, mobil radyonun sürekli olarak açık kalmasına ve pil gücünün hızla tükenmesine neden olabilir.
Üç genel türde düzenli güncelleme vardır:
- Kullanıcı tarafından başlatılır. Yenilemek için çekme hareketi gibi bazı kullanıcı davranışlarına dayalı bir güncelleme gerçekleştirme.
- Uygulama tarafından başlatıldı. Yinelenen bir güncelleme gerçekleştirme.
- Sunucu tarafından başlatılır. Bir sunucudan gelen bildirime yanıt olarak güncelleme yapma.
Bu konu, bunların her birine bakar ve pil tüketimini azaltmak için optimize edilebilecek ek yolları tartışır.
Kullanıcı tarafından başlatılan istekleri optimize etme
Kullanıcı tarafından başlatılan istekler genellikle bazı kullanıcı davranışlarına karşılık 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 yenilemek için çekme hareketi yapmasına olanak tanıyabilir. 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 azaltma
Gerekmediği durumlarda kullanıcı tarafından başlatılan bazı istekleri yoksayabilirsiniz. Örneğin, mevcut veriler henüz güncelken yeni veriler olup olmadığını kontrol etmek için kısa bir süre içinde birden fazla yenileme hareketi yapılması gibi. Her isteği yerine getirmek, radyoyu açık tutarak önemli miktarda güç israfına neden olabilir. Daha verimli bir yaklaşım, kullanıcı tarafından başlatılan istekleri sınırlandırarak bir süre boyunca yalnızca bir istek gönderilmesini sağlamaktır. Bu sayede radyonun kullanım sıklığı azaltılabilir.
Önbellek kullanma
Uygulamanızın verilerini önbelleğe alarak uygulamanızın referans alması gereken bilgilerin yerel bir kopyasını oluşturursunuz. Ardından uygulamanız, yeni istekler göndermek için 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 dahil olmak üzere verileri mümkün olduğunca agresif bir şekilde önbelleğe almanız gerekir. Önbelleğe alma stratejinizin uygulamanızın eski veriler göstermesine neden olmaması için HTTP önbelleğe alma ü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, makine öğrenimi ve medya oynatma gibi kullanım alanları için diğer uygulamaların 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 ilk olarak önbelleğe alınmış bir sürümü kontrol edebilir. Paylaşılan veri kümeleri hakkında daha fazla bilgi edinmek için Paylaşılan veri kümelerine erişim başlıklı makaleyi inceleyin.
Daha az sıklıkta daha fazla veri indirmek için daha yüksek bant genişliği kullanın
Kablosuz radyo üzerinden bağlanıldığında, daha yüksek bant genişliği genellikle daha yüksek pil maliyeti anlamına gelir. Yani 5G, genellikle LTE'den daha fazla enerji tüketir ve LTE de 3G'den daha pahalıdır.
Bu, temel radyo durumu radyo teknolojisine göre değişse de genel olarak durum değişikliği son zamanının pil üzerindeki göreceli etkisinin daha yüksek bant genişliğine sahip radyolar için daha büyük olduğu anlamına gelir. Kuyruk süresi hakkında daha fazla bilgi için Radyo durumu makinesi bölümüne bakın.
Aynı zamanda, daha yüksek bant genişliği, daha agresif ön getirme yapabileceğiniz ve aynı süre içinde daha fazla veri indirebileceğiniz anlamına gelir. Son zamanlı pil maliyeti nispeten daha yüksek olduğundan, güncellemelerin sıklığını azaltmak için her aktarım oturumunda radyoyu daha uzun süre etkin tutmak da daha verimlidir.
Örneğin, bir LTE radyo, 3G'nin bant genişliğinin ve enerji maliyetini iki katına çıkarıyorsa her oturum sırasında dört kat daha fazla veya 10 MB'a kadar veri indirmeniz gerekir. Bu kadar fazla veri indirirken, önceden getirme işleminin mevcut yerel depolama alanı üzerindeki etkisini göz önünde bulundurmak ve önceden getirme önbelleğini düzenli olarak temizlemeniz önemlidir.
Varsayılan ağ için bir dinleyici kaydetmek üzere ConnectivityManager
, mevcut cihaz bağlantı türünü belirlemek için ise TelephonyManager
PhoneStateListener
kaydetmek üzere 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 arka uç hizmetine günlük veya analiz gönderen bir uygulama gibi planlı olarak gerçekleşir. Uygulama tarafından başlatılan isteklerle çalışı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 ertelenebilir olup olmadığını göz önünde bulundurun. Bu istekler, dikkatli bir planlamayla ve WorkManager gibi kitaplıklar kullanılarak optimize edilebilir.
Toplu ağ istekleri
Mobil cihazlarda radyo açma, bağlantı kurma ve radyoyu açık tutma işlemleri çok fazla güç tüketir. Bu nedenle, isteklerin rastgele zamanlarda işlenmesi önemli miktarda güç tüketimine neden olabilir ve pil ömrünü kısaltabilir. Daha verimli bir yaklaşım, bir dizi ağ isteğini sıraya ekleyip birlikte işlemek olacaktır. Bu sayede sistem, radyoyu açmanın güç maliyetini yalnızca bir kez öder ve uygulamanın istediği tüm verileri almaya devam eder.
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 iş yapmak için WorkManager
kitaplığını kullanabilirsiniz. Örneğin, en son haber başlıklarını alan DownloadHeadlinesWorker
adlı bir Worker
alt sınıfınız olduğunu varsayalım. Bu işleyici, cihazın sınırsız bir ağa bağlı olması ve pil seviyesinin düşük olmaması koşuluyla her saat çalıştırılacak şekilde planlanabilir. Verileri almayla ilgili herhangi bir sorun olursa özel bir yeniden deneme stratejisi uygulanır. Bu strateji aşağıda gösterilmiştir:
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'a ek olarak, anket gibi ağ görevlerini tamamlamak için verimli bir program oluşturmanıza yardımcı olacak başka araçlar da sunar. Bu araçları kullanma hakkında daha fazla bilgi edinmek için Arka planda işleme rehberi'ne bakın.
Sunucu tarafından başlatılan istekleri optimize etme
Sunucu tarafından başlatılan istekler genellikle bir sunucudan gelen 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 grubuyla ilgili bildirim alabilir ve bu makaleleri indirebilir.
Firebase Cloud Messaging ile sunucu güncellemeleri gönderme
Firebase Cloud Messaging (FCM), bir sunucudan belirli bir uygulama örneğine veri aktarmak için kullanılan hafif bir mekanizmadır. Sunucunuz, FCM'yi kullanarak belirli bir cihazda çalışan uygulamanızı yeni verilerin kullanılabilir olduğu konusunda bilgilendirebilir.
Uygulamanızın yeni veri sorgulamak için düzenli olarak sunucuya ping göndermesi gereken yoklamaya kıyasla bu etkinliğe dayalı model, uygulamanızın yalnızca indirilecek veri olduğunu bildiği zaman 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 sayede kalıcı bağlantıların sayısı en aza indirilir ve platformun bant genişliğini optimize etmesine ve pil ömrü üzerindeki etkisini en aza indirmesine olanak tanınmış olur.