注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術(shù)一般,由于喜愛(ài)安卓而產(chǎn)生了翻譯的念頭,純屬個(gè)人興趣愛(ài)好。
原文鏈接: http://developer.android.com/training/efficient-downloads/efficient-network-access.html
在你的應(yīng)用中,可能最消耗電力的就是用無(wú)線網(wǎng)絡(luò)對(duì)資源進(jìn)行下載了。?為了最小化網(wǎng)絡(luò)連接對(duì)電池?fù)p耗的影響,你一定要理解你的連接模型是如何影響底層的的無(wú)線硬件的。這節(jié)課將介紹“無(wú)線網(wǎng)絡(luò)狀態(tài)機(jī)”并解釋你的應(yīng)用連接模型如何與這個(gè)狀態(tài)機(jī)聯(lián)系起來(lái)。緊接著我們會(huì)介紹如何減少你的數(shù)據(jù)連接,使用預(yù)取( use prefetching )和捆綁傳輸( bundle )讓數(shù)據(jù)傳輸對(duì)電池壽命的影響降低到最低。
一). 無(wú)線狀態(tài)機(jī)
一個(gè)完全活躍的無(wú)線連接會(huì)顯著地消耗電量,所以它會(huì)在不同的能耗狀態(tài)間切換,這樣做的目的是在它沒(méi)有被使用時(shí)可以節(jié)省電量,同時(shí)又能保證可以在盡量短的時(shí)間內(nèi)重新啟動(dòng)無(wú)線電。
對(duì)于一個(gè)標(biāo)準(zhǔn)的3G無(wú)線網(wǎng)絡(luò)來(lái)說(shuō),它的狀態(tài)機(jī)由三個(gè)能耗狀態(tài)組成:
- 高能耗 :當(dāng)一個(gè)連接處于活躍狀態(tài)時(shí)使用,允許設(shè)備在其最高的傳輸速率下傳輸數(shù)據(jù)。
- 低能耗 :一個(gè)中間的狀態(tài),其功率損耗大致為高能耗狀態(tài)的50%。
- 待機(jī) :最低的能耗狀態(tài),這種情況下沒(méi)有活躍的或者需要的網(wǎng)絡(luò)連接。
雖然低能耗及待機(jī)狀態(tài)會(huì)顯著減少電量的消耗,但他們也會(huì)在網(wǎng)絡(luò)連接請(qǐng)求發(fā)起時(shí)導(dǎo)致巨大的延遲。從低能耗狀態(tài)回到高能耗狀態(tài)需要大約1.5秒,而從待機(jī)狀態(tài)回到高能耗狀態(tài)則需要大約2秒甚至更多的時(shí)間。
為了將延遲最小化,狀態(tài)機(jī)使用了一個(gè)延遲機(jī)制,來(lái)推遲由高能耗到低能耗這一狀態(tài)切換。圖1所示的是 AT&T對(duì)于標(biāo)準(zhǔn)3G網(wǎng)絡(luò)的狀態(tài)機(jī)時(shí)間參數(shù):
圖1. 標(biāo)準(zhǔn)的3G無(wú)線網(wǎng)絡(luò)狀態(tài)機(jī)
每個(gè)設(shè)備上的無(wú)線狀態(tài)機(jī),尤其是狀態(tài)切換的延遲時(shí)間(尾時(shí)間“ tail time” )以及啟動(dòng)時(shí)間會(huì)隨著所采用的無(wú)線技術(shù)的不同而變化(2G,3G,LTE等),這些參數(shù)都由設(shè)備所支持的網(wǎng)絡(luò)運(yùn)營(yíng)商所定義和配置。
這節(jié)課將會(huì)講解一個(gè)具有代表性的標(biāo)準(zhǔn)3G網(wǎng)絡(luò)無(wú)線狀態(tài)機(jī),它基于AT&T所提供的 數(shù)據(jù) 。然而,這一思想及實(shí)踐方法對(duì)于所有的無(wú)線網(wǎng)絡(luò)的實(shí)現(xiàn)來(lái)說(shuō)也是可以應(yīng)用的。
這里所使用的這一狀態(tài)機(jī)對(duì)于網(wǎng)頁(yè)瀏覽來(lái)說(shuō)是非常有效的,因?yàn)樗粫?huì)在瀏覽網(wǎng)頁(yè)時(shí)引入用戶無(wú)法接受的長(zhǎng)延遲。較短的狀態(tài)切換時(shí)間也可以是的一旦一個(gè)瀏覽網(wǎng)頁(yè)的會(huì)話完畢了,無(wú)線網(wǎng)絡(luò)會(huì)轉(zhuǎn)換到低能耗狀態(tài)。
不幸的是,這種方法會(huì)導(dǎo)致一個(gè)現(xiàn)代智能手機(jī)操作系統(tǒng)上(如Android)的低效應(yīng)用,因?yàn)閼?yīng)用即在前臺(tái)運(yùn)行(控制延遲異常重要),也在后臺(tái)運(yùn)行(對(duì)電池壽命的影響)。
二). 應(yīng)用如何影響無(wú)線狀態(tài)機(jī)
每次你創(chuàng)建一個(gè)新的網(wǎng)絡(luò)連接,都會(huì)切換到高能耗狀態(tài)。在上面所說(shuō)的標(biāo)準(zhǔn)3G的無(wú)線狀態(tài)機(jī)而言,它在高能耗狀態(tài)所維持的時(shí)間為:數(shù)據(jù)傳輸時(shí)間+額外的5秒切換延遲,緊接著是低能耗狀態(tài)下的12秒切換延遲。也就是說(shuō),對(duì)于一個(gè)典型的3G設(shè)備,每次數(shù)據(jù)傳輸會(huì)話將會(huì)導(dǎo)致無(wú)線電消耗電量的時(shí)間長(zhǎng)達(dá)20秒左右。
在實(shí)際情況下,這意味著一個(gè)應(yīng)用如果不把要傳輸?shù)臄?shù)據(jù)打包,并每隔18秒傳輸1秒的數(shù)據(jù),那么就會(huì)然無(wú)線電一直處于活躍狀態(tài),在它即將回到待機(jī)狀態(tài)時(shí),又回到了高能耗狀態(tài)。它導(dǎo)致的結(jié)果就是:每分鐘內(nèi),會(huì)以高能耗狀態(tài)消耗電量18秒,剩下的42秒為低能耗狀態(tài)消耗電量的時(shí)間。
作為對(duì)比,同樣一個(gè)應(yīng)用如果將要傳輸?shù)臄?shù)據(jù)打包,每分鐘傳輸3秒的數(shù)據(jù),那么高能耗狀態(tài)只保持8秒,低能耗狀態(tài)只保持12秒。
上述第二個(gè)例子允許無(wú)線電在每分鐘內(nèi)有40秒處于待機(jī)狀態(tài),這回顯著減少電量的消耗。
圖2. 打包傳輸數(shù)據(jù)和不打包傳輸數(shù)據(jù)時(shí),無(wú)線電的電量使用對(duì)比
三). 預(yù)取數(shù)據(jù)
預(yù)取數(shù)據(jù)是一種非常有效的減少獨(dú)立數(shù)據(jù)傳輸?shù)臅?huì)話數(shù)目的方法。預(yù)取允許你一次性下載在給定時(shí)間內(nèi)你可能會(huì)使用的所有數(shù)據(jù)。
通過(guò)提前加載你的數(shù)據(jù),可以減少下載數(shù)據(jù)所需要的無(wú)線連接數(shù)。與此同時(shí),你不但節(jié)省了電量,也優(yōu)化了延遲,減少了帶寬的占用并減少了下載時(shí)間。
預(yù)取也可以減少由在顯示數(shù)據(jù)時(shí)等待下載完成所造成的延遲。這可以有效提升用戶體驗(yàn)。
然而,如果使用的太過(guò)度,預(yù)取也會(huì)引入過(guò)量消耗電池和帶寬使用的風(fēng)險(xiǎn),這是因?yàn)檫^(guò)度預(yù)取可能會(huì)取回來(lái)一些根本不需要的數(shù)據(jù)。另外還要確保預(yù)取不會(huì)造成應(yīng)用的啟動(dòng)延遲,因?yàn)閼?yīng)用可能會(huì)等待預(yù)取結(jié)束。就實(shí)際應(yīng)用而言,這意味著應(yīng)該要逐步地處理數(shù)據(jù),或者說(shuō)初始化傳輸?shù)膬?yōu)先級(jí),如應(yīng)用啟動(dòng)時(shí)需要的數(shù)據(jù)應(yīng)該優(yōu)先被下載。
執(zhí)行預(yù)取的程度取決于要被下載的數(shù)據(jù)規(guī)模以及數(shù)據(jù)被使用的可能性。粗略地來(lái)說(shuō),基于上述狀態(tài)機(jī)所描述的,對(duì)于當(dāng)前會(huì)話中有大約50%幾率使用的數(shù)據(jù),你可以先預(yù)取6秒鐘左右(大約1-2Mb),6秒時(shí)間的確定指的是在下載無(wú)用數(shù)據(jù)所消耗的時(shí)間和不下載這些數(shù)據(jù)所節(jié)省的時(shí)間相等時(shí)(此時(shí)預(yù)取已經(jīng)無(wú)法節(jié)約時(shí)間了)。
通常來(lái)說(shuō),預(yù)取數(shù)據(jù)時(shí),可以每2-5分鐘初始化另一個(gè)下載,來(lái)下載大約1-5Mb的數(shù)據(jù)。
遵循上述宗旨,大規(guī)模的下載——如視頻文件,應(yīng)該分塊以固定時(shí)間間隔分別下載(比如每2-5分鐘下載一塊數(shù)據(jù)),僅下載極有可能在后幾分鐘會(huì)觀看的視頻數(shù)據(jù)。
注意更多下載需要打包下載,這會(huì)在下一節(jié)詳細(xì)展開(kāi),具體的實(shí)現(xiàn)會(huì)根據(jù)連接的類型和速度而變化,這也會(huì)在后續(xù)課程中講到。
下面看一些實(shí)際例子:
音樂(lè)播放器:
你當(dāng)然可以一下子把整個(gè)專輯預(yù)取下來(lái),然而如果用戶聽(tīng)完第一首歌后就停止不聽(tīng)了,那么你就消耗了大量的貸款和電池壽命。
一個(gè)更好的措施是在當(dāng)前正在播放的歌曲之外,維持一個(gè)裝有凌一首歌曲的緩存。對(duì)于流媒體音樂(lè),可以使用HTTP流來(lái)傳輸音頻,預(yù)取操作可以用上述所說(shuō)的。
新聞閱讀器:
許多新聞應(yīng)用會(huì)嘗試通過(guò)再一種類型的新聞被選中后,僅下載標(biāo)題的方法來(lái)減少帶寬,只有在用戶選擇相應(yīng)的新聞后再下載文章,只有在用戶滑動(dòng)到顯示圖片的位置時(shí)再加載圖片。
通過(guò)這種方法,無(wú)線連接會(huì)一直保持活躍狀態(tài),因?yàn)橛脩魰?huì)不停地在標(biāo)題間切換,改變新聞?lì)悇e,并且閱讀文章。不僅如此,在能耗狀態(tài)發(fā)生切換時(shí),用于如果切換類別或閱讀文章會(huì)導(dǎo)致顯著的延遲。
一個(gè)更好的方法是在啟動(dòng)時(shí)先預(yù)取合理數(shù)量的數(shù)據(jù)。比如開(kāi)始可以先取最先的一批新聞標(biāo)題和縮略圖——保證啟動(dòng)的延遲時(shí)間較短——之后再陸續(xù)獲取標(biāo)題和縮略圖,以及相關(guān)的正文。
還有一種做法是預(yù)取每一個(gè)標(biāo)題,縮略圖,正文,甚至新聞完整的圖片——可以在后臺(tái)參照一個(gè)預(yù)定的時(shí)間表執(zhí)行。但是這個(gè)方法會(huì)消耗掉大量的帶寬和電量去下載那些從來(lái)不被使用的內(nèi)容,所以以這種方式實(shí)現(xiàn)的時(shí)候一定要格外的注意。
實(shí)現(xiàn)時(shí),一種方法是僅在有Wi-Fi連接的時(shí)候,還可能是僅在設(shè)備在充電的時(shí)候執(zhí)行。具體的細(xì)節(jié)在這篇文章中有闡述: Modify your Download Patterns Based on the Connectivity Type 。
四). 批量傳輸和連接
每一次你初始化一個(gè)連接——不論傳輸?shù)臄?shù)據(jù)量有多大——你都會(huì)導(dǎo)致無(wú)線電消耗大約20秒左右的電量(在使用一個(gè)標(biāo)準(zhǔn)3G無(wú)線網(wǎng)時(shí))。
如果一個(gè)應(yīng)用每20秒ping一次服務(wù)器,確認(rèn)應(yīng)用處于正在運(yùn)行并對(duì)用戶可見(jiàn)的狀態(tài),會(huì)導(dǎo)致無(wú)線電一直消耗電量,即使沒(méi)有實(shí)際的數(shù)據(jù)傳輸,也會(huì)消耗掉大量的電量。
綜上所述,打包你的數(shù)據(jù)傳輸是很重要的并創(chuàng)建一個(gè)帶傳輸?shù)年?duì)列。如果實(shí)現(xiàn)正確,你可以有效地在一時(shí)間窗口內(nèi)進(jìn)行數(shù)據(jù)傳輸,讓他們同時(shí)發(fā)生,以盡量保證數(shù)據(jù)傳輸在短時(shí)間內(nèi)做完。
這背后的哲學(xué)意義便是在傳輸數(shù)據(jù)量相同的情況下,要盡量使用最少的會(huì)話數(shù)目來(lái)完成所有數(shù)據(jù)的傳輸。
所以說(shuō),你應(yīng)該對(duì)于那些可以容忍有一定延遲的數(shù)據(jù)傳輸任務(wù)執(zhí)行批量傳輸,同時(shí)要記得當(dāng)對(duì)于時(shí)間敏感的傳輸任務(wù)需要做時(shí),它可以具有更高的優(yōu)先級(jí)去做更新或者預(yù)取等操作。計(jì)劃的更新和預(yù)取任務(wù)應(yīng)該開(kāi)始于你的延遲傳輸隊(duì)列。
對(duì)于一個(gè)實(shí)際的例子,讓我們回到之前預(yù)取數(shù)據(jù)中的例子。
對(duì)于一個(gè)采用了上述預(yù)取策略的新聞應(yīng)用。新聞閱讀器收集并分析信息來(lái)理解其用戶的閱讀模式,并標(biāo)記出用戶最喜歡的文章類型。為了保證該部分文章一直是最新的,它每隔一個(gè)小時(shí)就刷新一次。為了保留帶寬,它并不是下載每篇文章的所有圖片,而是僅下載縮略圖,并在用戶選擇了以后再下載完整的圖片。
在這個(gè)例子中,所有應(yīng)用收集的分析信息被捆綁在一起,并排成隊(duì)列等待傳輸,而不是一收集到就傳輸。捆綁好的數(shù)據(jù)的傳輸時(shí)機(jī),可以是當(dāng)一副完整的圖片下載好了,或者每隔一小時(shí)的更新發(fā)生時(shí)(將數(shù)據(jù)傳輸?shù)娜蝿?wù)合并在一起)。
所有對(duì)時(shí)間敏感的或者點(diǎn)播類型的數(shù)據(jù)傳輸——比如下載一幅完整的圖片,需要優(yōu)先于常規(guī)的計(jì)劃任務(wù)。計(jì)劃更新的執(zhí)行時(shí)機(jī)應(yīng)該是在設(shè)置好的計(jì)劃間隔時(shí)間過(guò)了之后隨著緊急的數(shù)據(jù)傳輸一起發(fā)生。這種方法通過(guò)將計(jì)劃更新和對(duì)時(shí)間敏感的下載圖片等任務(wù)捆綁在一起,來(lái)減輕執(zhí)行計(jì)劃更新的代價(jià)。
五). 減少連接數(shù)
通常來(lái)說(shuō),使用已經(jīng)存在的網(wǎng)絡(luò)連接會(huì)比重新初始化一個(gè)新的網(wǎng)絡(luò)連接來(lái)說(shuō)更有效率。重復(fù)使用連接還能是的網(wǎng)絡(luò)對(duì)于擁塞和相關(guān)的網(wǎng)絡(luò)數(shù)據(jù)問(wèn)題的響應(yīng)可以更加智能。
你應(yīng)該將請(qǐng)求捆綁到一個(gè)GET當(dāng)中,而不是創(chuàng)建多個(gè)連接同時(shí)下載數(shù)據(jù),或多個(gè)連接連續(xù)的發(fā)送GET請(qǐng)求。
例如,為每一個(gè)新聞標(biāo)題生成單一的請(qǐng)求,并返回單一的請(qǐng)求或響應(yīng)會(huì)比生成多個(gè)請(qǐng)求要好。無(wú)線需要保持活躍來(lái)傳輸端到端之間的確認(rèn)接受包,所以在不用網(wǎng)絡(luò)連接的時(shí)候應(yīng)該將其關(guān)閉,而不是讓它一直開(kāi)啟并等待超時(shí)信息。
也就是說(shuō),如果過(guò)早地關(guān)閉一個(gè)連接會(huì)阻止它被重用,這就需要額外的消耗來(lái)建立新的連接。一個(gè)折中的方案是不要立即關(guān)閉這些連接,不過(guò)還是要在超時(shí)時(shí)間到之前將其關(guān)閉。
六). 使用DDMS的網(wǎng)絡(luò)流量工具來(lái)確定哪里可以改進(jìn)
Android? DDMS (Dalvik Debug Monitor Server) 包含有一個(gè)詳細(xì)的網(wǎng)絡(luò)使用工具,使得其能夠在你的應(yīng)用發(fā)出網(wǎng)絡(luò)連接請(qǐng)求時(shí)跟蹤網(wǎng)絡(luò)情況。使用這個(gè)工具,你可以監(jiān)測(cè)你的應(yīng)用是在何時(shí)以什么方式傳輸數(shù)據(jù)的,并可以根據(jù)監(jiān)測(cè)的結(jié)果優(yōu)化你的代碼實(shí)現(xiàn)。
圖3展示了一個(gè)每隔15秒鐘傳輸一次少量數(shù)據(jù)的場(chǎng)景,從中可以發(fā)現(xiàn)通過(guò)預(yù)取或者批量傳輸?shù)姆椒梢燥@著提高應(yīng)用的傳輸效率:
圖3. 使用DDMS跟蹤網(wǎng)絡(luò)使用情況
通過(guò)監(jiān)聽(tīng)你的數(shù)據(jù)傳輸?shù)念l率,以及每次傳輸數(shù)據(jù)時(shí)的數(shù)據(jù)量,之后你就能找到你的應(yīng)用可以在什么地方加以改進(jìn)來(lái)提高電池的使用效率。通常而言,你可以找一些可以延遲的波峰,對(duì)其進(jìn)行延遲。或者將一些傳輸任務(wù)提前。
為了更好的表現(xiàn)出傳輸導(dǎo)致波峰的原因,可以使用 Traffic Stats API在一個(gè)線程內(nèi)使用 TrafficStats.setThreadStatsTag() 方法,人工地標(biāo)記或者取消標(biāo)記某一個(gè)套接字(使用 tagSocket() 方法和 untagSocket() 方法 ),來(lái)標(biāo)記數(shù)據(jù)傳輸?shù)陌l(fā)生。例如:
TrafficStats.setThreadStatsTag(0xF00D ); TrafficStats.tagSocket(outputSocket); // Transfer data using socket TrafficStats.untagSocket(outputSocket);
Apache的 HttpClient 和 URLConnection 庫(kù)可以基于當(dāng)前的 getThreadStatsTag() 的值自動(dòng)地為套接字做標(biāo)記。這些庫(kù)還能在套接字在活動(dòng)池中循環(huán)后自動(dòng)地進(jìn)行標(biāo)記或取消標(biāo)記。
TrafficStats.setThreadStatsTag(0xF00D ); try { // Make network request using HttpClient.execute() } finally { TrafficStats.clearThreadStatsTag(); }
套接字標(biāo)記在Android 4.0中開(kāi)始被支持,但是實(shí)時(shí)的數(shù)據(jù)顯示僅能在運(yùn)行Android 4.0.3或更高版本系統(tǒng)的設(shè)備上被顯示。
【Android Developers Training】 83. 實(shí)現(xiàn)高效網(wǎng)絡(luò)訪問(wèn)來(lái)優(yōu)化下載
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
