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.
Düzenli olarak yapılan üç genel güncelleme türü 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ılan. Düzenli olarak güncelleme yapma.
- Sunucu tarafından başlatıldı. Sunucudan gelen bildirime yanıt olarak güncelleme yapma.
Bu bölümde bunların her biri ele alınmış ve pil tüketimini azaltmak için bunların optimize edilebileceği diğer yöntemler ele alınmaktadır.
Kullanıcı tarafından başlatılan istekleri optimize edin
Kullanıcı tarafından başlatılan istekler genellikle bazı kullanıcı davranışlarına yanıt olarak ortaya çıkar. Ö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 kısıtlayın
Kullanıcı tarafından başlatılan bazı istekleri (ör. mevcut veriler hâlâ yeniyken yeni verileri kontrol etmek için kısa bir süre boyunca birden fazla yenilemek için çekme hareketi) göz ardı edebilirsiniz. Her istek üzerine işlem yapmak, radyoyu açık tutarak önemli miktarda güç israfına neden olabilir. Daha etkili bir yaklaşım, kullanıcı tarafından başlatılan istekleri kısmaktır. Böylece belirli bir süre boyunca yalnızca bir istek gönderilebilir. Böylece, radyonun kullanım sıklığı azalır.
Önbellek kullanma
Uygulamanızın verilerini önbelleğe alarak, uygulamanızın referans vermesi gereken bilgilerin yerel bir kopyasını oluşturursunuz. Böylece uygulamanız, 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 görüntüler gibi isteğe bağlı indirmeler dahil olmak üzere, verileri mümkün olduğunca agresif bir şekilde önbelleğe almalısınız. Önbelleğe alma stratejinizin, uygulamanızda eski veriler göstermesine engel olmak için HTTP önbellek başlıklarını kullanabilirsiniz. Ağ yanıtlarını önbelleğe alma hakkında daha fazla bilgi için Gereksiz indirmeleri önleme bölümüne bakın.
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şme bölümünü 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ğlandığında, daha yüksek bant genişliği genellikle daha yüksek pil maliyetiyle sonuçlanır. Yani 5G, genellikle LTE'den daha fazla enerji tüketir. Bu da 3G'den daha pahalıdır.
Bu, temel radyo durumu radyo teknolojisine göre değişse de, genel anlamda durum değişikliği bekleme süresinin göreli pil etkisi, yüksek bant genişliğine sahip radyolar için daha fazla 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 bir şekilde önceden getirme ve aynı anda daha fazla veri indirebileceğiniz anlamına gelir. Arka planda pil maliyeti nispeten daha yüksek olduğundan, güncellemelerin sıklığını azaltmak için radyoyu her aktarım oturumu sırasında daha uzun süre etkin tutmak da daha verimli olabilir.
Örneğin, bir LTE radyo, 3G'nin bant genişliği 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 getirmenin mevcut yerel depolama alanı üzerindeki etkisini göz önünde bulundurmak ve önceden getirme önbelleğini düzenli olarak temizlemeniz önemlidir.
Varsayılan ağa bir işleyici kaydetmek için ConnectivityManager
simgesini, mevcut cihaz bağlantı türünü belirlemek üzere bir PhoneStateListener
işleyici kaydetmek için TelephonyManager
simgesini 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 edin
Uygulama tarafından başlatılan istekler genellikle bir plana göre gerçekleşir (ör. arka uç hizmetine günlük veya analizler gönderen uygulamalar). Uygulama tarafından başlatılan istekleri ele alırken bu isteklerin önceliğini, birlikte gruplandırılıp gruplandırılamayacağını ve cihaz şarj olana veya sayaçsız bir ağa bağlanana kadar ertelenip ertelenemeyeceğini göz önünde bulundurun. Bu istekler, dikkatli bir planlamayla ve WorkManager gibi kitaplıklar kullanılarak optimize edilebilir.
Toplu ağ istekleri
Mobil cihazlarda, radyoyu açma, bağlantı kurma ve radyoyu açık tutma işlemleri çok fazla güç tüketir. Bu nedenle, isteklerin tek tek rastgele işlenmesi, önemli miktarda güç tüketebilir ve pil ömrünü azaltabilir. Bir dizi ağ isteğini sıraya almak ve birlikte işlemek daha verimli bir yaklaşımdır. Bu durumda sistem, radyoyu açmanın güç maliyetini yalnızca bir kez öder ve uygulamanın istediği tüm verileri yine de alır.
WorkManager'ı kullanma
Ağ kullanılabilirliği ve güç durumu gibi belirli koşulların karşılanıp karşılanmadığını değerlendiren verimli bir program üzerinde çalışmak için WorkManager
kitaplığını kullanabilirsiniz. Örneğin, en son haber başlıklarını alan DownloadHeadlinesWorker
adında bir Worker
alt sınıfınızın olduğunu varsayalım. Bu çalışan, cihazın sınırsız bir ağa bağlı olması ve pil seviyesinin düşük olmaması koşuluyla, aşağıda gösterildiği gibi verilerin alınmasında herhangi bir sorun olması durumunda özel bir yeniden deneme stratejisi ile her saat başı çalışacak şekilde planlanabilir:
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 yoklama 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 edin
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 uyan yeni bir makale grubu hakkında bildirim alabilir ve uygulamayı indirir.
Firebase Cloud Messaging ile sunucu güncellemeleri gönderin
Firebase Cloud Messaging (FCM), bir sunucudan belirli bir uygulama örneğine veri aktarmak için kullanılan basit bir mekanizmadır. Sunucunuz, FCM'yi kullanarak belirli bir cihazda çalışan uygulamanıza kendisi için yeni veriler olduğunu bildirebilir.
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ğ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 yaşanan 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 ilgili etkiyi en aza indirmesine olanak tanır.