Düzenli güncellemelerin etkisini en aza indirme

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.