鍍金池/ 教程/ Android/ 優(yōu)化下載以高效地訪問網(wǎng)絡(luò)
檢測常用的手勢
優(yōu)化layout的層級
用戶輸入
管理應(yīng)用的內(nèi)存
聯(lián)系人信息
開發(fā)輔助程序
Android多媒體
添加語音功能
顯示位置地址
提供向下與橫向?qū)Ш?/span>
支持游戲控制器
訪問可穿戴數(shù)據(jù)層
處理多點觸控手勢
全屏沉浸式應(yīng)用
為多線程創(chuàng)建管理器
數(shù)據(jù)保存
Intent的發(fā)送
更新Notification
優(yōu)化下載以高效地訪問網(wǎng)絡(luò)
打印
打包可穿戴應(yīng)用
接收從其他App傳送來的數(shù)據(jù)
發(fā)送與接收消息
建立靈活動態(tài)的UI
處理鍵盤輸入
Building a Work Policy Controller
建立測試環(huán)境
創(chuàng)建表盤
分享文件
顯示Notification進(jìn)度
實現(xiàn)自適應(yīng)UI流(Flows)
使用設(shè)備管理策略增強安全性
使用能感知版本的組件
執(zhí)行網(wǎng)絡(luò)操作
建立文件分享
添加移動
更新你的Security Provider來對抗SSL漏洞利用
支持鍵盤導(dǎo)航
創(chuàng)建和監(jiān)視地理圍欄
發(fā)送并同步數(shù)據(jù)
使用BigView樣式
無線連接設(shè)備
提供向上導(dǎo)航與歷史導(dǎo)航
最小化定期更新造成的影響
實現(xiàn)向下的導(dǎo)航
支持不同的屏幕大小
Android 可穿戴應(yīng)用
添加動畫
顯示聯(lián)系人頭像
使用OpenGL ES顯示圖像
處理輸入法可見性
分享文件
保持設(shè)備喚醒
淡化系統(tǒng)Bar
使用NFC分享文件
保存到Preference
Android聯(lián)系人信息與位置信息
創(chuàng)建標(biāo)準(zhǔn)的網(wǎng)絡(luò)請求
使用Drawables
管理Bitmap的內(nèi)存使用
管理Activity的生命周期
按需加載視圖
傳輸資源
為可穿戴設(shè)備創(chuàng)建自定義UI
在一個線程中執(zhí)行一段特定的代碼
性能優(yōu)化
隱藏導(dǎo)航欄
創(chuàng)建目錄瀏覽器
為多種大小的屏幕進(jìn)行規(guī)劃
View間漸變
使用觸摸手勢
高效加載大圖
使用CursorLoader在后臺加載數(shù)據(jù)
創(chuàng)建抽屜式導(dǎo)航(navigation drawer)
管理音頻焦點
創(chuàng)建后臺服務(wù)
創(chuàng)建功能測試
創(chuàng)建使用Material Design的應(yīng)用
停止與重啟Activity
添加一個簡便的分享功能
啟動Activity時保留導(dǎo)航
TV應(yīng)用清單
創(chuàng)建向后兼容的UI
?# 優(yōu)化自定義View
創(chuàng)建單元測試
在UI上顯示Bitmap
建立OpenGL ES的環(huán)境
構(gòu)建表盤服務(wù)
JNI Tips
建立搜索界面
實現(xiàn)自定義View的繪制
使用HTTPS與SSL
按需操控BroadcastReceiver
分享簡單的數(shù)據(jù)
繪制形狀
Android位置信息
創(chuàng)建并運行可穿戴應(yīng)用
執(zhí)行 Sync Adpater
獲取最后可知位置
創(chuàng)建 Android 項目
實現(xiàn)高效的導(dǎo)航
退出全屏的Activity
創(chuàng)建Card
兼容音頻輸出設(shè)備
同步數(shù)據(jù)單元
傳輸數(shù)據(jù)時避免消耗大量電量
保存到文件
緩存Bitmap
提供配置 Activity
調(diào)度重復(fù)的鬧鐘
實現(xiàn)輔助功能
重復(fù)的下載是冗余的
隱藏狀態(tài)欄
實現(xiàn)自定義的網(wǎng)絡(luò)請求
規(guī)劃界面和他們之間的關(guān)系
使用Sync Adapter傳輸數(shù)據(jù)
TV應(yīng)用內(nèi)搜索
響應(yīng)觸摸事件
使用Google Cloud Messaging(已廢棄)
控制相機(jī)
Android網(wǎng)絡(luò)連接與云服務(wù)
請求分享一個文件
處理TV硬件
響應(yīng)UI可見性的變化
使用網(wǎng)絡(luò)服務(wù)發(fā)現(xiàn)
指定輸入法類型
優(yōu)化電池壽命
創(chuàng)建TV應(yīng)用
獲取聯(lián)系人列表
拖拽與縮放
啟動與停止線程池中的線程
創(chuàng)建 Sync Adpater
使用 WiFi P2P 服務(wù)發(fā)現(xiàn)
開始使用Material Design
代理至新的APIs
使用include標(biāo)簽重用layouts
使得View可交互
高效顯示Bitmap
創(chuàng)建企業(yè)級應(yīng)用
Fragments之間的交互
創(chuàng)建與執(zhí)行測試用例
綜合:設(shè)計我們的樣例 App
繪制表盤
建立簡單的用戶界面
自定義動畫
開發(fā)輔助服務(wù)
避免出現(xiàn)程序無響應(yīng)ANR(Keeping Your App Responsive)
使用ViewPager實現(xiàn)屏幕滑動
設(shè)計高效的導(dǎo)航
Android分享操作(Building Apps with Content Sharing)
提供向后的導(dǎo)航
保持向下兼容
創(chuàng)建TV播放應(yīng)用
縮放View
使用 WiFi 建立 P2P 連接
Android后臺任務(wù)
連接到網(wǎng)絡(luò)
為 Notification 添加頁面
使TV應(yīng)用是可被搜索的
添加Action Bar
使用Material的主題
啟動另一個Activity
顯示正在播放卡片
適配不同的系統(tǒng)版本
輕松錄制視頻
創(chuàng)建可穿戴的應(yīng)用
創(chuàng)建自定義的布局
重新創(chuàng)建Activity
使用CursorLoader執(zhí)行查詢?nèi)蝿?wù)
使用舊的APIs實現(xiàn)新API的效果
使用備份API
安全要點
Android入門基礎(chǔ):從這里開始
保存并搜索數(shù)據(jù)
根據(jù)網(wǎng)絡(luò)連接類型來調(diào)整下載模式
使用Tabs創(chuàng)建Swipe視圖
SMP(Symmetric Multi-Processor) Primer for Android
解析 XML 數(shù)據(jù)
使用 Volley 傳輸網(wǎng)絡(luò)數(shù)據(jù)
建立ActionBar
Android交互設(shè)計
使用Intent修改聯(lián)系人信息
增加搜索功能
輕松拍攝照片
定義形狀
測試你的Activity
在 Notifcation 中接收語音輸入
與其他應(yīng)用的交互
管理系統(tǒng)UI
追蹤手勢移動
Android界面設(shè)計
執(zhí)行 Android 程序
顯示確認(rèn)界面
創(chuàng)建Lists與Cards
打印HTML文檔
創(chuàng)建TV應(yīng)用
為多屏幕設(shè)計
定義Shadows與Clipping視圖
使用Fragment建立動態(tài)UI
接收Activity返回的結(jié)果
布局變更動畫
定位常見的問題
自定義ActionBar的風(fēng)格
定義Layouts
發(fā)送簡單的網(wǎng)絡(luò)請求
啟動與銷毀Activity
與UI線程通信
非UI線程處理Bitmap
創(chuàng)建TV布局
提升Layout的性能
報告任務(wù)執(zhí)行狀態(tài)
判斷并監(jiān)測網(wǎng)絡(luò)連接狀態(tài)
兼容不同的設(shè)備
處理按鍵動作
優(yōu)化性能和電池使用時間
給其他App發(fā)送簡單的數(shù)據(jù)
Implementing App Restrictions
向后臺服務(wù)發(fā)送任務(wù)請求
展示Card翻轉(zhuǎn)動畫
管理ViewGroup中的觸摸事件
兼容不同的屏幕密度
通過藍(lán)牙進(jìn)行調(diào)試
為可穿戴設(shè)備創(chuàng)建Notification
控制音量與音頻播放
獲取聯(lián)系人詳情
在表盤上顯示信息
提供向上的導(dǎo)航
滾動手勢動畫
幫助用戶在TV上找到內(nèi)容
創(chuàng)建TV導(dǎo)航
為索引指定App內(nèi)容
ActionBar的覆蓋疊加
Android Wear 上的位置檢測
保護(hù)安全與隱私的最佳策略
Ensuring Compatibility with Managed Profiles
解決云同步的保存沖突
獲取位置更新
創(chuàng)建List
測試程序
管理網(wǎng)絡(luò)的使用情況
為App內(nèi)容開啟深度鏈接
推薦TV內(nèi)容
建立一個Notification
管理音頻播放
設(shè)計表盤
拍照
處理控制器輸入動作
判斷并監(jiān)測設(shè)備的底座狀態(tài)與類型
處理查詢的結(jié)果
保存到數(shù)據(jù)庫
支持多個游戲控制器
創(chuàng)建 Stub Content Provider
使得ListView滑動順暢
處理數(shù)據(jù)層的事件
創(chuàng)建TV應(yīng)用的第一步
使得你的App內(nèi)容可被Google搜索
將 Notification 放成一疊
創(chuàng)建 Stub 授權(quán)器
暫停與恢復(fù)Activity
管理設(shè)備的喚醒狀態(tài)
Android圖像與動畫
打印照片
云同步
創(chuàng)建TV直播應(yīng)用
為Notification賦加可穿戴特性
提供一個Card視圖
建立請求隊列(RequestQueue)
適配不同的語言
創(chuàng)建詳情頁
測試UI組件
接收其他設(shè)備的文件
創(chuàng)建自定義View
建立第一個App
創(chuàng)建2D Picker
監(jiān)測電池的電量與充電狀態(tài)
打印自定義文檔
抽象出新的APIs
通知提示用戶
獲取文件信息
運用投影與相機(jī)視角
在IntentService中執(zhí)行后臺任務(wù)
多線程操作
創(chuàng)建一個Fragment
添加Action按鈕
在不同的 Android 系統(tǒng)版本支持控制器
維護(hù)兼容性
發(fā)送文件給其他設(shè)備
創(chuàng)建TV游戲應(yīng)用
創(chuàng)建自定義的View類
代碼性能優(yōu)化建議
Intent過濾
適配不同的屏幕

優(yōu)化下載以高效地訪問網(wǎng)絡(luò)

編寫:kesenhoo - 原文:http://developer.android.com/training/efficient-downloads/efficient-network-access.html

使用無線電波(wireless radio)進(jìn)行傳輸數(shù)據(jù)很可能是我們 app 最耗電的來源之一。為了最小化網(wǎng)絡(luò)連接對電量的消耗,懂得連接模式(connectivity model)會如何影響底層的無線電硬件設(shè)備是至關(guān)重要的。

這節(jié)課介紹了無線電波狀態(tài)機(jī)(wireless radio state machine),并解釋了 app 的連接模式是如何與狀態(tài)機(jī)進(jìn)行交互的。然后會提出建議的方法來最小化我們的數(shù)據(jù)連接,使用預(yù)?。╬refetching)與捆綁(bundle)的方式進(jìn)行數(shù)據(jù)的傳輸,這些操作都是為了最小化電量的消耗。

無線電波狀態(tài)機(jī)

一個處于完全工作狀態(tài)的無線電會大量消耗電量,因此需要學(xué)習(xí)如何在不同能量狀態(tài)下進(jìn)行過渡,當(dāng)無線電沒有工作時,節(jié)省電量,當(dāng)需要時嘗試最小化與無線電波供電有關(guān)的延遲。

典型的 3G 無線電網(wǎng)絡(luò)有三種能量狀態(tài):

  1. Full power:當(dāng)無線連接被激活的時候,允許設(shè)備以最大的傳輸速率進(jìn)行操作。
  2. Low power:一種中間狀態(tài),對電量的消耗差不多是 Full power 狀態(tài)下的50%。
  3. Standby:最小的能量狀態(tài),沒有被激活或者需求的網(wǎng)絡(luò)連接。

在低功耗和空閑的狀態(tài)下,電量消耗會顯著減少。這里也會介紹重要的網(wǎng)絡(luò)請求延遲。從 low power 能量狀態(tài)返回到 full power 大概需要花費1.5秒,從空閑能量狀態(tài)返回到 full power 狀態(tài)需要花費2秒。

為了最小化延遲,狀態(tài)機(jī)使用了一種后滯過渡到更低能量狀態(tài)的機(jī)制。下圖是一個典型的 3G 無線電波狀態(tài)機(jī)的圖示(AT&T電信的一種制式)。

http://wiki.jikexueyuan.com/project/android-training-geek/images/mobile_radio_state_machine.png" alt="mobile_radio_state_machine.png" title="Figure 1. Typical 3G wireless radio state machine." />

Figure 1. 典型的 3G 無線電狀態(tài)機(jī)

在每一臺設(shè)備上的無線狀態(tài)機(jī),特別是相關(guān)的傳輸延遲(“拖尾時間”)和啟動延遲,都會根據(jù)無線電波的制式(2G、3G、LTE等)不同而改變,并且由設(shè)備正在所使用的網(wǎng)絡(luò)進(jìn)行定義與配置。

這一課描述了一種典型的 3G 無線電波狀態(tài)機(jī),數(shù)據(jù)來源于 AT&T。無論如何,這些原理和最佳實踐結(jié)果是具有通用性的,在其他的無線電波上同樣適用。

這種方法在典型的網(wǎng)頁瀏覽操作上是特別有效的,因為它可以阻止用戶在瀏覽網(wǎng)頁時的一些不受歡迎的延遲。相對較短的拖尾時間也保證了當(dāng)一個網(wǎng)頁瀏覽會話結(jié)束的時候,無線電波可以轉(zhuǎn)移到相對較低的能量狀態(tài)。

不幸的是,這個方法會導(dǎo)致在現(xiàn)代的智能機(jī)系統(tǒng)例如 Android 上的 app 效率低下。因為 Android 上的 app 不僅僅可以在前臺運行(重點關(guān)注延遲),也可以在后臺運行(優(yōu)先處理耗電量)。(無線電波的狀態(tài)改變會影響到本來的設(shè)計,有些想在前臺運行的可能會因為切換到低能量狀態(tài)而影響程序效率。坊間說手機(jī)在電量低的狀態(tài)下無線電波的強度會增大好幾倍來保證信號,可能與這個有關(guān)。)

App 如何影響無線電波狀態(tài)機(jī)

每次創(chuàng)建一個新的網(wǎng)絡(luò)連接,無線電波就切換到 full power 狀態(tài)。在上面典型的 3G 無線電波狀態(tài)機(jī)情況下,無線電波會在傳輸數(shù)據(jù)時保持在 full power 的狀態(tài),加上一個附加的5秒拖尾時間,再之后會經(jīng)過12秒進(jìn)入到 low power 能量狀態(tài)。因此對于典型的 3G 設(shè)備,每一次數(shù)據(jù)傳輸?shù)臅挾紩?dǎo)致無線電波消耗大概20秒時間來提取電能。

實際上,這意味著一個每18秒傳輸1秒非捆綁數(shù)據(jù)(unbundled data)的 app,會一直保持激活狀態(tài)(18 = 1秒的傳輸數(shù)據(jù) + 5秒過渡時間回到 low power + 12秒過渡時間回到standby)。因此,每分鐘會消耗18秒 high power 的電量,42秒 low power 的電量。

通過比較,同一個 app,每分鐘傳輸持續(xù)3秒的捆綁數(shù)據(jù)(bundle data),會使得無線電波持續(xù)在 high power 狀態(tài)僅僅8秒,在 low power 狀態(tài)僅僅12秒鐘。

上面第二種傳輸捆綁數(shù)據(jù)(bundle data)的例子,可以看到減少了大量的電量消耗。圖示如下:

http://wiki.jikexueyuan.com/project/android-training-geek/images/graphs.png" alt="graphs.png" title="Figure 2. Relative wireless radio power use for bundled versus unbundled transfers." />

Figure 2. 無線電波使用捆綁數(shù)據(jù) vs 無線電波使用非捆綁數(shù)據(jù)

預(yù)取數(shù)據(jù)

預(yù)取數(shù)據(jù)是一種減少獨立數(shù)據(jù)傳輸會話數(shù)量的有效方法。預(yù)取技術(shù)指的是在一定時間內(nèi),單次連接操作,以最大的下載能力來下載所有用戶可能需要的數(shù)據(jù)。

通過前面的傳輸數(shù)據(jù)的技術(shù),減少了大量下載數(shù)據(jù)所需的無線電波激活時間。這樣不僅節(jié)省了電量,也改善了延遲,降低了帶寬,減少了下載時間。

預(yù)取技術(shù)通過減少應(yīng)用里由于在執(zhí)行一個動作或者查看數(shù)據(jù)之前等待下載完成造成的延遲,來提高用戶體驗。

然而,過于頻繁地使用預(yù)取技術(shù),不僅僅會導(dǎo)致電量消耗快速增長,還有可能預(yù)取到一些并不需要的數(shù)據(jù),導(dǎo)致增加帶寬的使用和下載配額。另外,需要確保預(yù)取不會因為 app 等待預(yù)取全部完成而延遲應(yīng)用的啟動。從實踐的角度,那意味著需要逐步處理數(shù)據(jù),或者按照優(yōu)先級順序開始進(jìn)行持續(xù)的數(shù)據(jù)傳遞,這樣會首先下載和處理應(yīng)用啟動時需要的數(shù)據(jù)。

根據(jù)正在下載的數(shù)據(jù)大小與可能被用到的數(shù)據(jù)量來決定預(yù)取的頻率。作一個粗略的估計,根據(jù)上面介紹的狀態(tài)機(jī),對于有50%的機(jī)會被當(dāng)前的用戶會話用到的數(shù)據(jù),我們可以預(yù)取大約6秒(大約1-2Mb),這大概使得潛在可能要用的數(shù)據(jù)量與可能已經(jīng)下載好的數(shù)據(jù)量相一致。

通常來說,預(yù)取1-5Mb會比較好,這種情況下,我們僅僅只需要每隔2-5分鐘開始另一段下載。

根據(jù)這個原理,大數(shù)據(jù)的下載,比如視頻文件,應(yīng)該每隔2-5分鐘開始另一段下載,這樣能有效的預(yù)取到下面幾分鐘內(nèi)的數(shù)據(jù)進(jìn)行預(yù)覽。

值得注意的是,更進(jìn)一步的下載應(yīng)該是是捆綁的(bundled),下一小節(jié)將會講到,批量處理傳送和連接,而且上面那些大概的數(shù)據(jù)與時間可能會根據(jù)網(wǎng)絡(luò)連接的類型與速度有所變化,這將在根據(jù)網(wǎng)絡(luò)連接類型來調(diào)整下載模式講到。

讓我們來看一些例子:

一個音樂播放器

我們可以選擇預(yù)取整個專輯,然而這樣在第一首歌曲之后用戶會停止聽歌,那么就浪費了大量的帶寬和電量。

一個比較好的方法是維護(hù)正在播放的那首歌曲的緩沖區(qū)。對于流媒體音樂,不應(yīng)該去維護(hù)一段連續(xù)的數(shù)據(jù)流,因為這樣會使得無線電波一直保持激活狀態(tài),而應(yīng)該考慮用 HTTP 流直播來集中傳輸音頻流,就像上面描述的預(yù)取技術(shù)一樣(下載好2Mb,然后開始一次取出,再去下載下面的2Mb)。

一個新聞閱讀器

許多新聞 app 嘗試通過只下載新聞標(biāo)題來減少帶寬,完整的文章僅在用戶想要讀取的時候再去讀取,而且文章也會因為太長而剛開始只顯示部分信息,等用戶下滑時再去讀取完整信息。

使用這個方法,無線電波僅僅會在用戶點擊更多信息的時候才會被激活。但是,在切換文章分類預(yù)閱讀文章的時候仍然會造成大量潛在的消耗。

一個比較好的方法是在啟動的時候預(yù)取一個合理數(shù)量的數(shù)據(jù),比如在啟動的時候預(yù)取第一條新聞的標(biāo)題與縮略圖信息,確保較短的啟動時間。之后繼續(xù)獲取剩余新聞的標(biāo)題和縮略圖信息。同時獲取至少在主要標(biāo)題列表中可用的每篇文章的文本。

另一個方法是預(yù)取所有的標(biāo)題,縮略信息,文章文字,甚至是所有文章的圖片——根據(jù)既設(shè)的后臺程序進(jìn)行逐一獲取。這樣做的風(fēng)險是花費了大量的帶寬與電量去下載一些不會閱讀到的內(nèi)容,因此應(yīng)該謹(jǐn)慎使用這種方法。

其中的一個解決方案是,僅當(dāng)在連接至Wi-Fi或者設(shè)備正在充電時,調(diào)度到 Full power 狀態(tài)進(jìn)行下載。關(guān)于這個細(xì)節(jié)的實現(xiàn),我們將在后面的根據(jù)網(wǎng)絡(luò)連接類型來調(diào)整下載模式課程中介紹。

批量處理傳送和連接

每次發(fā)起一個連接——不論相關(guān)傳送數(shù)據(jù)的大小——當(dāng)使用典型的 3G 無線網(wǎng)絡(luò)時,可能會導(dǎo)致無線電波消耗大約20秒的電量。

一個 app 每20秒 ping 一次服務(wù)器,僅僅是為了確認(rèn) app 正在運行和對用戶可見,那么無線電波會無限期地處于開啟狀態(tài),導(dǎo)致即使在沒有實際數(shù)據(jù)傳輸?shù)那闆r下,仍會消耗大量電量。

因此,對傳送的數(shù)據(jù)進(jìn)行捆綁操作和創(chuàng)建一個等待傳輸隊列就顯得非常重要。操作正確的話,可以使得大量的數(shù)據(jù)集中進(jìn)行發(fā)送,這樣使得無線電波的激活時間盡可能的少,同時減少大部分電量的花費。

這樣做的潛在好處是盡可能在每次傳輸數(shù)據(jù)的會話中盡可能多的傳輸數(shù)據(jù)而且減少了會話的次數(shù)。

那就意味著我們應(yīng)該通過隊列延遲容忍傳送來批量處理我們的傳輸數(shù)據(jù),和搶占調(diào)度更新和預(yù)取,使得當(dāng)要求時間敏感傳輸時,數(shù)據(jù)會被全部執(zhí)行。同樣地,我們的計劃更新和定期的預(yù)取應(yīng)該開啟等待傳輸隊列的執(zhí)行工作。

預(yù)取數(shù)據(jù)部分有一個實際的例子。

以上述使用定期預(yù)取的新聞應(yīng)用為例。新聞閱讀器收集分析用戶的信息來了解用戶的閱讀模式,并按照新聞報道的受歡迎程度對新聞進(jìn)行排序。為了保證新聞最新,應(yīng)用每個小時會檢查更新一次。為了節(jié)省帶寬,預(yù)取縮略圖信息和當(dāng)用戶選擇某個新聞時下載全部圖片,而不去下載每篇文章的所有圖片。

在這個例子中,所有在 app 中收集到的分析信息應(yīng)該捆綁在一起并放入下載隊列,而不是一收集到信息就傳輸。當(dāng)下載完一張全尺寸的圖片或者執(zhí)行每小時一次更新時,應(yīng)該傳輸捆綁好的數(shù)據(jù)。

任何時間敏感或者按需的傳輸——例如下載全尺寸圖片——應(yīng)該搶占定期更新。計劃好的更新應(yīng)該與按需傳送在同一時間執(zhí)行。這個方法減小了執(zhí)行一個定期更新的開銷,該定期更新通過下載必要的時間敏感圖片的背負(fù)式傳輸實現(xiàn)。

減少連接

通常來說,重用已經(jīng)存在的網(wǎng)絡(luò)連接比起重新建立一個新的連接更有效率。重用網(wǎng)絡(luò)連接同樣可以使得在擁擠不堪的網(wǎng)絡(luò)環(huán)境中進(jìn)行更加智能地作出反應(yīng)。

當(dāng)可以捆綁所有請求在一個 GET 里面的時候,不要同時創(chuàng)建多個網(wǎng)絡(luò)連接或者把多個 GET 請求進(jìn)行串聯(lián)。

例如,可以一起請求所有文章的情況下,不要根據(jù)多個新聞會話進(jìn)行多次請求。為傳輸與服務(wù)端和客戶端 timeout 相關(guān)的終止 / 終止確認(rèn)數(shù)據(jù)包,無線電波會保持激活狀態(tài),所以如果不需要使用連接時,請立即關(guān)閉,而不是等待他們 timeout。

之前說道,如果過早對一個連接執(zhí)行關(guān)閉操作,會導(dǎo)致需要額外的開銷來建立一個新的連接。一個有用的妥協(xié)是不要立即關(guān)閉連接,而是在固定期間的 timeout 之前關(guān)閉(即稍微晚點卻又不至于到 timeout)。

使用 DDMS Network Traffic Tool 來確定問題的區(qū)域

Android DDMS (Dalvik Debug Monitor Server) 包含了一個查看網(wǎng)絡(luò)使用詳情的欄目來允許跟蹤 app 的網(wǎng)絡(luò)請求。使用這個工具,可以監(jiān)測 app 是在何時,如何傳輸數(shù)據(jù)的,從而進(jìn)行代碼的優(yōu)化。

Figure 3 顯示了傳輸少量數(shù)據(jù)的網(wǎng)絡(luò)模型,可以看到每次差不多相隔15秒,這意味著可以通過預(yù)取技術(shù)或者批量上傳來大幅提高效率。

http://wiki.jikexueyuan.com/project/android-training-geek/images/DDMS.png" alt="DDMS.png" title="Figure 3. Tracking network usage with DDMS." />

Figure 3. 使用 DDMS 檢測網(wǎng)絡(luò)使用情況

通過監(jiān)測數(shù)據(jù)傳輸?shù)念l率與每次傳輸?shù)臄?shù)據(jù)量,可以查看出哪些位置應(yīng)該進(jìn)行優(yōu)化。通常的,我們會尋找類似短穗狀的地方,這些位置可以延遲,或者應(yīng)該導(dǎo)致一個后來的傳輸被搶占。

為了更好的檢測出問題所在,Traffic Status API 允許我們使用 TrafficStats.setThreadStatsTag() 方法標(biāo)記數(shù)據(jù)傳輸發(fā)生在某個Thread里面,然后可以手動地使用 tagSocket() 進(jìn)行標(biāo)記或者使用 untagSocket()` 來取消標(biāo)記,例如:

TrafficStats.setThreadStatsTag(0xF00D);
TrafficStats.tagSocket(outputSocket);
// Transfer data using socket
TrafficStats.untagSocket(outputSocket);

Apache 的 HttpClientURLConnection 庫可以根據(jù)當(dāng)前的 getThreadStatusTag() 值自動給 sockets 加上標(biāo)記。那些庫在通過 keep-alive pools 循環(huán)的時候也會為 sockets 加上或者取消標(biāo)簽。

TrafficStats.setThreadStatsTag(0xF00D);
try {
  // Make network request using HttpClient.execute()
} finally {
  TrafficStats.clearThreadStatsTag();
}

給 Socket 加上標(biāo)簽(Socket tagging)是在 Android 4.0 上才被支持的, 但是實際情況是僅僅會在運行Android 4.0.3 或者更高版本的設(shè)備上才會顯示。