在當前WiFi普及的大環境下,我們很容易忽略網絡的問題,特別是在我們在室內測試的時候。
基於下面三個原因,我們有必要做網絡優化
有效地網絡使用能夠提高用戶體驗。
有效使用網絡能夠大幅減少電量使用,因網絡傳輸數據是電量消耗的一個最重要的來源。
有效的網絡使用有時候能夠顯著減少佔用帶寬。
簡單的優化
訪問網絡之前,先檢測網絡是否可用
- 通過ConnectivityMananger來判斷
- 通過Broadcast Receiver監聽網路變化。
下載優化
1.優化下載機制
Radio State Machine.
上圖是使用AT&T的3G信號的計時情況,資料來自於efficient-network-access
Full power: 當網絡連接激活時,設備可以以最大可能的速率傳輸數據
Low Power:Full power的使用50%電量的點狀態。
Standby:最小的能量狀態,當沒有網絡使用申請或者網絡被激活。
因爲APP每次創建一個網絡connections,從連接到關閉會經歷上圖中的Radio State Machine.下圖是對比不綁定數據傳輸和綁定數據傳輸的使用情況:
綁定數據傳輸會讓Radio大多數時候處於standby。
在這個設計原則的指引下,我們應該儘可能做到,預先獲取需要的數據,儘可能把需要的數據綁定傳輸給APP端,重用網絡連接(把多個HTPP GET請求壓縮到一個HTPP GET請求)。下面舉幾個例子
音樂播放器,在播放音樂的同時,通過突發傳輸流的方式保持一首歌的緩衝,而不是一次性下載整個專輯,這樣會讓網絡連接一直保持在激活狀態。
新聞閱讀器,在不影響APP體驗的前提下,預先下載用戶可能需要用到的新聞列表(至少是推薦列表)的標題,內容,縮略圖,大圖應該在用戶點擊縮略圖的時候再去下載。
視頻,每隔2-5分鐘預先緩衝接下來幾分鐘用戶要看到的視頻幀。
下面是可以幫助實現批量處理網絡使用的工具
2.優化數據更新請求,這裏的更新包括數據更新和版本更新,通過下面幾點做到
- 沒有網絡的時候,停止後臺的更新請求
- 當電量低的時候,減少更新頻率
- 用推送代替輪詢,來查詢服務器是否有新數據。
- 如果要使用輪詢,可以使用 JobScheduler, AlarmManager, and Firebase JobDispatcher
3.優化冗餘的下載,通過下面幾點做到。
通過RESTfull API的設計原則,儘量做到API只傳輸需要的數據。最常見的例子就是,列表和詳情,列表API應該僅僅包括當前顯示要的數據,詳情API應該是另外一個包含更多信息的。不合理的設計中,列表API會包含詳情API。
服務端應該提供,根據所需尺寸獲取對應大小的圖片,七牛已經幫我們實現了。使用WebP格式;同樣的照片,採用WebP格式可大幅節省流量,相對於JPG格式的圖片,流量能節省將近 25% 到 35 %;相對於 PNG 格式的圖片,流量可以節省將近80%。最重要的是使用WebP之後圖片質量也沒有改變
緩存經常使用的數據,前提是必須保證這個數據是最新的,可以通過如下代碼實現
// url represents the website containing the content to place into the cache.
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
long currentTime = System.currentTimeMillis();
long expires = conn.getHeaderFieldDate("Expires", currentTime);
long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);
// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
// Skip update
} else {
// Parse update
lastUpdateTime = lastModified;
}
- 用增量升級代替全量升級,參考bugly的補丁升級
備註:敏感的數據可以存儲到app安裝目錄,非敏感數據可以存儲到sdcard,但是需要注意的是,如果存儲到APP安裝目錄,有可能會因爲手機內存緊張,而被某些工具清除掉。
4.根據網絡連接類型來修改相應的下載策略
這個原則,就是在網絡最好的情況下載最大的數據,下面代碼可以幫助我們理解
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
TelephonyManager tm =
(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
int PrefetchCacheSize = DEFAULT_PREFETCH_CACHE;
switch (activeNetwork.getType()) {
case (ConnectivityManager.TYPE_WIFI):
PrefetchCacheSize = MAX_PREFETCH_CACHE; break;
case (ConnectivityManager.TYPE_MOBILE): {
switch (tm.getNetworkType()) {
case (TelephonyManager.NETWORK_TYPE_LTE |
TelephonyManager.NETWORK_TYPE_HSPAP):
PrefetchCacheSize *= 4;
break;
case (TelephonyManager.NETWORK_TYPE_EDGE |
TelephonyManager.NETWORK_TYPE_GPRS):
PrefetchCacheSize /= 2;
break;
default: break;
}
break;
}
default: break;
}
5.使用網絡緩存
對服務端返回數據進行緩存,設定有效時間,有效時間之內不走網絡請求,減少流量消耗。對網絡的緩存可以參見HttpResponseCache
6.斷點下載和上傳
斷點續傳,文件、圖片等的下載,採用斷點續傳/下載,不浪費用戶之前消耗過的流量。最典型的例子就是斷點下載升級版本。
優化數據傳輸格式
重構數據傳輸
- 可以通過把請求數據zip壓縮的方式傳輸。
- 使用Protocol Buffers or FlatBuffers 替代gson, xml,因爲前兩者更加簡潔,輕量級。
優化上傳
大文件上傳,包括圖片,視頻等
大文件上傳失敗率比較高,,同時帶寬、時延、穩定性等因素在此場景下的影響也更加明顯;
避免整文件傳輸,採用分片傳輸;根據網絡類型以及傳輸過程中的變化動態的修改分片大小;每個分片失敗重傳的機會。
使用好工具
參考文檔:
https://developer.android.com/training/efficient-downloads/efficient-network-access.html
https://developer.android.com/topic/performance/power/network/action-any-traffic.html
https://developer.android.com/reference/android/net/http/HttpResponseCache.html