【Android Advanced Training - 05】傳輸數據時避免電量的浪費[Lesson 1 - 看無線電波如何影響網絡操作]


分類: Android 981人閱讀 評論(2) 收藏 舉報

Optimizing Downloads for Efficient Network Access

[用有效的網絡訪問來最優化下載]

  • 也許使用無線電波(wireless radio)進行傳輸數據會是我們app最耗電的操作之一。所以爲了最小化網絡連接的電量消耗,懂得連接模式(connectivity model)會如何影響底層的音頻硬件設備是至關重要的。
  • 這節課介紹了無線電波狀態機(wireless radio state machine),並解釋了app的connectivity model是如何與狀態機進行交互的。然後會提出建議的方法來最小化我們的數據連接,使用預取(prefetching)捆綁(bundle)的方式進行數據的傳輸,這些操作都是爲了最小化電量的消耗。

The Radio State Machine[無線電狀態機]

  • 一個完全活動的無線電會消耗很大部分的電量,因此需要學習如何在不同狀態下進行過渡,這樣能夠避免電量的浪費。
  • 典型的3G無線電網絡有三種能量狀態:
    • Full power: 當無線連接被激活的時候,允許設備以最大的傳輸速率進行操作。
    • Low power: 相對Full power來說,算是一種中間狀態,差不多50%的傳輸速率。
    • Standby: 最低的狀態,沒有數據連接需要傳輸。
  • 在最低並且空閒的狀態下,電量消耗相對來說是少的。
  • 這裏需要介紹一延時(latency)的機制,從low status返回到full status大概需要花費1.5秒,從idle status返回到full status需要花費2秒。
  • 爲了最小化延遲,狀態機使用了一種後滯過渡到更低能量狀態的機制。下圖是一個典型的3G無線電波狀態機的圖示(AT&T電信的一種制式).


  • 在每一臺設備上的無線狀態機都會根據無線電波的制式(2G,3G,LTE等)而改變,並且由設備本身自己所使用的網絡進行定義與配置。
  • 這一課描述了一種典型的3G無線電波狀態機,data provided by AT&T(http://www.research.att.com/articles/featured_stories/2011_03/201102_Energy_efficient?fbid=SYuI20FzBum)。這些原理是具有通用性的,在其他的無線電波上同樣適用。
  • 這種方法在瀏覽通常的網頁操作上是特別有效的,因爲它可以阻止一些不必要的浪費。而且相對較短的後期處理時間也保證了當一個session結束的時候,無線電波可以轉移到相對較低的能量狀態。
  • 不幸的是,這個方法會導致在現代的智能機系統例如Android上的apps效率低下。因爲Android上的apps不僅僅可以在前臺運行,也可以在後臺運行。[無線電波的狀態改變會影響到本來的設計,有些想在前臺運行的可能會因爲切換到低能量狀態而影響程序效率。坊間說手機在電量低的狀態下無線電波的強度會增大好幾倍來保證信號,可能與這個有關]

How Apps Impact the Radio State Machine[看apps如何影響無線狀態機(使用bundle與unbundle傳輸數據的差異)]

  • 每一次新創建一個網絡連接,無線電波就切換到full power狀態。在上面典型的3G無線電波狀態機情況下,無線電波會在傳輸數據時保持在full power的狀態,結束之後會有一個附加的5秒時間切換到low power,再之後會經過12秒進入到low  energy的狀態。因此對於典型的3G設備,每一次數據傳輸的會話都會引起無線電波都會持續消耗大概20秒的能量。
  • 實際上,這意味着一個app傳遞1秒鐘的unbundled data會使得無線電波持續活動18秒[18=1秒的傳輸數據+5秒過渡時間回到low power+12秒過渡時間回到standby]。因此每一分鐘,它會消耗18秒high power的電量,42秒的low power的電量。
  • 通過比較,如果每分鐘app會傳輸bundle的data持續3秒的話,其中會使得無線電波持續在high power狀態僅僅8秒鐘,在low power狀態僅僅12秒鐘。
  • 上面第二種傳輸bundle data的例子,可以看到減少了大量的電量消耗。圖示如下:


Prefetch Data[預取數據]

  • 預取(Prefetching)數據是一種減少獨立數據傳輸會話數量的有效方法。預取技術允許你在單次操作的時候,通過一次連接,在最大能力下,根據給出的時間下載到所有的數據。
  • 通過前面的傳輸數據的技術,你減少了大量的無線電波激活時間。這樣的話,不僅僅是保存了電量,也提高了潛在風險[看下面講解],降低了帶寬,減少了下載時間。
  • 預取技術提供了一種提高用戶體驗的方法,通過減少可能因爲下載時間過長而導致預覽後者後續操作等待漫長。
  • 然而,使用預取技術過於頻繁,不僅僅會導致電量消耗快速增長,還有可能預取到一些並不需要的數據[比如預取了10秒,用戶在第3秒就已經切換掉,這個時候預取過多的就是浪費]。同樣,確保app不會因爲等待預取全部完成而卡到程序的開始播放也是非常重要的。從實踐的角度,那意味着需要逐步處理數據,並且按照有優先級的順序開始進行數據傳遞,這樣能確保不卡到程序的開始播放的同時數據也能夠得到持續的下載。
  • 那麼應該如何控制預取的操作呢?這需要根據正在下載的數據大小與可能被用到的數據量來決定。一個基於上面狀態機情況的比較大概的建議是:對於數據來說,大概有50%的機會可能用在當前用戶的會話中,那麼我們可以預取大約6秒(大約1-2Mb),這大概使得潛在可能要用的數據量與可能已經下載好的數據量相一致。
  • 通常來說,預取1-5Mb會比較好,這種情況下,我們僅僅只需要每隔2-5分鐘開始另一段下載。[3G網絡是這樣嗎?]根據這個原理,大數據的下載,比如視頻文件,應該每隔2-5秒開始另一段下載,這樣能有效的預取到下面幾分鐘內的數據進行預覽。
  • 值得注意的是,下載需要是bundled的形式,而且上面那些大概的數據與時間可能會根據網絡連接的類型與速度有所變化,這些都將在下面兩部分內容講到。
  • 讓我們來看一些例子:
  1. A music player:
    • 你可以選擇預取整個專輯,然而這樣用戶在第一首歌曲之後停止監聽,那麼就浪費了大量的帶寬於電量。
    • 一個比較好的方法是維護一首歌曲的緩衝區。對於流媒體音樂,不應該去維護一段連續的數據流,因爲這樣會使得無線電波一直保持激活狀態,應該考慮把HTTP的數據流集中一次傳輸到音頻流,就像上面描述的預取技術一樣(下載好2Mb,然後開始一次取出,再去下載下面的2Mb)。
  2. A news reader:
    • 許多news apps嘗試通過只下載新聞標題來減少帶寬,完整的文章僅在用戶想要讀取的時候再去讀取,而且文章也會因爲太長而剛開始只顯示部分信息,等用戶下滑時再去讀取完整信息。
    • 使用這個方法,無線電波僅僅會在用戶點擊更多信息的時候纔會被激活。但是,在切換文章分類預閱讀文章的時候仍然會造成大量潛在的消耗。[因爲無線電波有幾十秒的過渡期]
    • 一個比較好的方法是在啓動的時候預取一個合理數量的數據,比如在啓動的時候預取一些文章的標題[免得切換分類時又去獲取這個欄目下的頭條]與縮略圖信息。之後開始獲取剩餘的標題預縮略信息。
    • 另一個方法是預取所有的標題,縮略信息,文章文字,甚至是所有文章的圖片-根據既設的後臺程序進行逐一獲取。這樣做的風險是花費了大量的帶寬與電量去下載一些不會閱讀到的內容,因此這需要比較小心思考是否合適。其中的一個解決方案是,當在連接至Wi-Fi時有計劃的下載所有的內容,並且如果有可能最好是設備正在充電的時候。關於這個的細節的實現,我們將在後面的課程中涉及到。[這讓我想起了網易新聞的離線下載,在連接到Wi-Fi的時候,可以選擇下載所有的內容到本地,之後直接打開閱讀]

Batch Transfers and Connections[批量傳輸與連接]

  • 使用典型3G無線網絡制式的時候,每一次初始化一個連接(與需要傳輸的數據量無關),你都有可能導致無線電波持續花費大約20秒的電量。
  • 一個app,若是每20秒進行一次ping server的操作,假設這個app是正在運行且對用戶可見,那麼這會導致無線電波不確定什麼時候被開啓,最終可能使得電量花費在沒有實際傳輸數據的情況下。
  • 因此,對數據進行bundle操作並且創建一個序列來存放這些bundle好的數據就顯的非常重要。操作正確的話,可以使得大量的數據集中進行發送,這樣使得無線電波的激活時間儘可能的少,同時減少大部分電量的花費。這樣做的潛在好處是儘可能在每次傳輸數據的會話中儘可能多的傳輸數據而且減少了會話的次數。
  • 例如:新聞客戶端可以分析用戶的使用行爲習慣,根據這些習慣來做決定如何獲取數據,獲取多少,什麼時候獲取等。在這個例子中,所有收集到的用戶習慣應該捆綁一起,之後再一起進行發送,而不是每次點擊的行爲都去發送這個碎片數據。[這讓我想到目前做的一個項目裏面應該可以考慮使用這種機制的,現在採取的方法太傻大粗了],同時,發送這些數據不應該在下載一個全圖或者執行例行更新的時候去操作。

Reduce Connections[減少連接次數]

  • 重用已經存在的網絡連接比起重新建立一個新的連接通常來說是更有效率的。重用網絡連接同樣可以使得在擁擠不堪的網絡環境中進行更加智能的互動。當可以捆綁所有請求在一個GET裏面的時候不要同時創建多個網絡連接或者把多個GET請求進行串聯。
  • 例如,可以一起請求所有文章的情況下,不要根據多個欄目進行多次請求。無線電波會在等待接受返回信息或者timeout信息之前保持激活狀態,所以如果不需要的連接請立即關閉而不是等待他們timeout。
  • 之前說道,如果關閉一個連接過於及時,會導致後面再次請求時重新建立一個在Server與Client之間的連接,而我們說過要儘量避免建立重複的連接,那麼有個有效的折中辦法是不要立即關閉,而是在timeout之前關閉(即稍微晚點卻又不至於到timeout)。

Use the DDMS Network Traffic Tool to Identify Areas of Concern[使用DDMS網絡通信工具來檢測關心的區域]

  • The Android DDMS (Dalvik Debug Monitor Server) 包含了一個查看網絡使用詳情的欄目來允許跟蹤app的網絡請求。使用這個工具,可以監測app是在何時,如何傳輸數據的,從而可以進行代碼的優化。
  • 下圖顯示了傳輸少量的網絡模型,可以看到每次差不多相隔15秒,這意味着可以通過預取技術或者批量上傳來大幅提高效率。

  • 通過監測數據傳輸的頻率與每次傳輸的數據量,可以查看出哪些位置應該進行優化,通常的,圖中顯示的短小的類似釘子形狀的位置,可以進行與附近位置的請求進行做merge的動作。
  • 爲了更好的檢測出問題所在,Traffic Status API允許你使用TrafficStats.setThreadStatsTag()的方法標記數據傳輸發生在某個Thread裏面,然後可以手動的使用tagSocket()進行標記到或者使用untagSocket()來取消標記,例如:
  1. <span style="font-family:'Microsoft YaHei';">TrafficStats.setThreadStatsTag(0xF00D);  
  2. TrafficStats.tagSocket(outputSocket);  
  3. // Transfer data using socket  
  4. TrafficStats.untagSocket(outputSocket);</span>  
  • Apache的HttpClientURLConnection庫可以自動tag sockets使用當前getThreadStatusTag()的值。那些庫在通過keep-alive pools循環的時候也會tag與untag sockets。
  1. <span style="font-family:'Microsoft YaHei';">TrafficStats.setThreadStatsTag(0xF00D);  
  2. try {  
  3.   // Make network request using HttpClient.execute()  
  4. finally {  
  5.   TrafficStats.clearThreadStatsTag();  
  6. }</span>  
  • Socket tagging 是在Android 4.0上才被支持的, 但是實際情況是僅僅會在運行Android 4.0.3 or higher的設備上纔會顯示.

後記:哇,這節課太長了,不過很值得我們學習並注意,Radio state machine,Prefetch,Bundle等,在實際項目中,可能很少有人注意到這些,這也是Google開設這一系列課程的價值所在,提高app的質量,用更少的資源做更多的事情。


發佈了17 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章