Düzenli güncellemelerin etkisini en aza indirme

Uygulamanızın ağa gönderdiği istekler pil tüketiminin önemli bir nedenidir çünkü güç tüketen hücresel veya kablosuz radyoları açtılar. Bu radyolar, paket gönderip almak için gereken gücün yanı sıra yalnızca açılmak ve açık kalmak için de ek güç harcar. 15 saniyede bir ağ isteği gibi basit bir işlem, mobil radyoyu sürekli açık tutabilir ve pil gücünü hızlıca tüketebilir.

Düzenli olarak yapılan üç genel güncelleme türü vardır:

  • Kullanıcı tarafından başlatılır. Yenileme için ekranı çekme gibi bazı kullanıcı davranışlarına dayalı güncelleme yapma
  • 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 birini ele alır ve bunları ele almanın yollarını optimize edilmiş bir uygulamadı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 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 makale olup olmadığını kontrol etmek için yenile simgesine dokunma 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 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ığı azalır.

Önbellek kullanma

Uygulamanızın verilerini önbelleğe alarak bilgilerin yerel bir kopyasını oluşturursunuz en iyi uygulamaları paylaşacağız. Böylece uygulamanız, bilgileri bir ağ açmak zorunda kalmadan birden çok kez kopyalamak bağlantıyı tıklayın.

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. HTTP kullanabilirsiniz engellemek için, önbelleğe alma stratejinizin uygulamanızla sonuçlanmasına neden olmaması için eski veriler görüntüleniyor. Ağ yanıtlarını önbelleğe alma hakkında daha fazla bilgi için Gereksiz indirmelerden kaçınma başlıklı makaleyi inceleyin.

Uygulamanız, Android 11 ve sonraki sürümlerde kullanım alanları için kullanılan uygulamalardan bahsedeceğiz. uygulamanın paylaşılan bir veri kümesine erişmesi gerekiyorsa önce uygulamanın önbelleğe alınmış bir sürümünü kontrol edebilir kontrol edin. 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 bir radyo üzerinden bağlandığında, daha yüksek bant genişliği genellikle daha yüksek pil maliyetidir. Diğer bir deyişle, 5G genelde daha fazla enerji tüketir. LTE'den daha pahalıya mal oluyor.

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. Son süre hakkında daha fazla bilgi için Radyo durum 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. Belki daha az daha yüksektir, çünkü kuyruk süresinde pil maliyeti nispeten daha yüksektir Böylece her aktarım sırasında radyonun daha uzun süre etkin kalması oturumlarını bir arada kullanma yollarını inceleyeceğiz.

Örneğin, bir LTE radyosunun bant genişliği ve enerji maliyeti 3G'nin iki katıysa her oturumda dört kat daha fazla veri indirmeniz gerekir. Bu miktar, 10 MB'a kadar çıkabilir. Bu kadar fazla veriyi indirirken Önceden getirme işleminin kullanılabilir yerel depolama ve temizleme üzerindeki etkisini göz önünde bulundurun düzenli olarak kontrol edebilirsiniz.

URL parametrelerinin Google tarafından nasıl ele alınmasını istediğinizi belirtmek için Kaydolmak için ConnectivityManager varsayılan ağ için bir işleyici ve Kaydolmak için TelephonyManager PhoneStateListener geçerli cihaz bağlantı türünü belirler. Bağlantı türü öğrenildiğinde ö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 arka uç hizmetine günlük veya analiz gönderen bir uygulama gibi planlı olarak gerçekleşir. Uygulama tarafından başlatılan bu isteklerin önceliğini göz önünde bulundurun. Bu isteklerin toplu halde mi ve cihaz şarj olana kadar veya cihaz şarj olana kadar sınırsız bir ağa bağlıdır. 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, çok fazla güç tüketir. İşte bu nedenle istekleri rastgele işlemek, önemli miktarda güç tüketebilir yardımcı olabilir. Daha verimli bir yaklaşım, bir dizi ağ isteğini sıraya ekleyip birlikte işlemek olacaktır. Bu, sistemin gereken gücü ödemesine olanak tanır. için yalnızca bir kez bile olsa radyoyu açmanın bir uygulamadı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ışma 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 çalışan Cihazın bir Özel bir yeniden deneme stratejisi sayesinde, sınırsız ağın ve cihazın pil seviyesinin düşük olması verileri alırken herhangi bir sorun olursa aşağıdaki adımları uygulayın:

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 birkaç başka araç da sunar. gibi ağ görevlerini tamamlamak için verimli bir zaman çizelgesi oluşturmanıza yardımcı olur. tercih eder. Bu araçları kullanma hakkında daha fazla bilgi edinmek için Arka planda işleme rehberi.

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 uygun yeni bir makale grubuyla ilgili bildirim alabilir ve bu makaleleri indirebilir.

Firebase Cloud Messaging ile sunucu güncellemeleri gönderin

Firebase Cloud Messaging (FCM) hafif bir bir sunucudan belirli bir uygulama örneğine veri iletmek için kullanılan mekanizma. Sunucunuz FCM'yi kullanarak belirli bir cihazda çalışan uygulamanızı bununla ilgili yeni veriler mevcut.

Uygulamanızın yeni verileri sorgulamak için sunucuyu düzenli olarak pinglemesi gereken ankete kıyasla bu olaya dayalı model, uygulamanızın yalnızca indirilecek veri olduğunu bildiği durumlarda yeni bir bağlantı oluşturmasına olanak tanır. Model, gereksiz bilgi sayısını en aza indirir. ve uygulamanızdaki bilgiler güncellenirken 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.