深入探索 Android 網絡優化(三、網絡優化篇)上

前言

成爲一名優秀的Android開發,需要一份完備的知識體系,在這裏,讓我們一起成長爲自己所想的那樣~。

本文思維導圖

一、網絡優化維度

1、網絡優化分析

基礎網絡的效率就像一輛列車,時延是火車的速度 (啓動時間),而帶寬就像火車的車廂裝載量,整個傳輸的物理鏈路就像火車的鐵軌。從網絡的通信過程來看,共涉及到 三個模塊

  • 1)、網絡庫 SDK 內部的設計與策略:I/O 併發模型,針對網絡問題的優化
  • 2)、服務器性能:併發、帶寬能力
  • 3)、網絡相關:用戶網絡(弱網/強網)、運營商、網絡鏈路等

而對於網絡的優化,我們可以從以下五個維度來進行。

1)、流量優化

精確獲取網絡流量的消耗量,解決整體均值掩蓋單點異常流量的問題。

2)、網絡監控

建設全面的網絡監控,因爲粗粒度的監控不能夠幫助我們發現和解決問題。

3)、流量消耗

  • 1、精準獲取一段時間的流量消耗、網絡類型、前後臺。
  • 2、用戶流量消耗均值、異常率(消耗多、次數多)。
  • 3、完整鏈路全監控(Request、Response)、主動上報。

4)、網絡請求質量

  • 1、請求時長、業務成功率、失敗率、TOP 失敗接口,導致請求失敗的原因通常有兩種情況:
    • 1)、弱信號:可以簡單看成手機信號只有一兩格的時候,這是不僅僅是信令(無線網絡通信的都是一個個的信令)發出去困難,還可能導致不斷切換網絡、基站。App 只能在應用層做重試,因爲弱信號一般都是一時的。
    • 2)、擁塞網絡:可以類比爲堵車、排隊的場景,數據包排隊,信令也在排隊。這時 App 不斷重試,只會使得擁塞網絡更爲嚴重。我們只能讓自己的非核心業務不要去排隊,並讓核心業務的數據量更少,協議來回更少。
  • 2、用戶體驗
  • 3、請求速度、成功率:網絡正常時如何更好地利用帶寬提升網絡請求速度?
  • 4、弱網:網絡不穩定是如何最大程度上保證網絡的連通性?
  • 5、安全:如何防止被第三方劫持、竊聽甚至篡改?

5)、其它

  • 1、公司成本
  • 2、帶寬、服務器數量、CDN
  • 3、耗電

2、網絡優化誤區

  • 1)、僅僅關注流量消耗,忽視其它維度。
  • 2)、僅僅關注均值、整體、忽視個體。

二、網絡優化工具

1、Network Profiler

特點

  • 1)、顯示實時網絡活動:發送、接收數據及連接數。
  • 2)、需啓動高級分析。
  • 3)、僅支持 HttpURLConnection 與 OkHttp

打開高級分析

Run => Edit Cofigurations => 界面最右邊 Profiling => 打開 Enable advanced profiling (required for API level < 26 only)

使用 Network Profiler 調試 WanAndroid 網絡請求

選中目標網絡請求,可以看到在下方的 Connection View 一欄看到對應的網絡數據,如下所示:

  • Size
  • Type
  • Status
  • Time
  • Timeline

選中 Connection View 特定的一條數據即可在右邊看到該請求對應的網絡數據。

Overview

該網絡請求的預覽信息

普通 Json 數據請求

圖片加載請求

Response

Response Header 與 Body 信息

Request

Request Header 與 Body 信息

CallStack

網絡請求的調用堆棧信息, 下圖就是 Awesome-WanAndroid 發起一個網絡請求所經歷的調用堆棧:

Awesome-WanAndroid 使用 Glide 發起一個圖片加載請求所經歷的調用堆棧:

關鍵細節

高級配置中的 required for API level < 26 only 不是限定調試的手機版本小於26,我使用 API 27 的手機也可以調試。

實踐中獲得的新知識及感悟

如果想快速搞懂接手項目中的網絡/圖片加載等框架的w網絡請求流程,可以使用 Profiler NETWORK 的 CallStack 功能,並且雙擊其中任意的一行調用鏈方法都可以 jump to 指定源碼。

選中網絡請求無法顯示數據?

打開高級分析即可。

2、Charles

使用 Java 開發的,MAC 上使用較多。

特點

  • 1)、斷點功能
  • 2)、Map Local
  • 3)、弱網環境模擬

安裝配置

1、下載 Charles

2、截獲手機端的網絡包。

需要配置手機與電腦連接同一 WIFI。

1)、電腦端設置 Charles — 打開 HTTP 代理並設置代理端口
  • Charles 菜單欄 => Proxy => Proxy Settings => 填代理端口 8888 並勾選 Enable transparent HTTP proxying。
2)、手機端設置 WIFI 代理及端口
  • 獲取電腦 IP 地址
    • 點擊 Charles 的 help => local address。
  • 設置 WIFI 代理及端口號
    • 手機設置 => WLAN => 查看當前連接的 WIFI 詳情 => 最底部代理項設置爲手動 => 配置 電腦 IP 地址與端口號8888。
3)、設置完成,運行任意聯網程序,Charles 會彈出請求連接的確認框,點擊 allow 即可。

3、截取 HTTPS

需要信任 Charles 的 CA 證書。

1)、打開 SSL 代理,並配置 Host 與 Port
  • 電腦端 Proxy => SSL Proxying Setting => 選中 Enable SSL Proxying 並點擊 Add 配置 Host 與 Port 分半爲 * 與 443。
2)、信任 Charles Proxy CA 機構
  • 電腦端 Help => SSL Proxying => Install Charles Root Certificate => 選中並雙擊 Charles Proxy CA 根證書頒發機構 => 點擊信任 => 使用此證書時選擇始終信任。
3)、手機端安裝 Charles 頒發的 SSL 證書
  • 電腦端 Help => SSL Proxying => Install Charles Root Certificate on a Mobile Device,此時會彈出提示框讓手機端訪問 http://chls.pro/ssl 去下載證書。
4)、手機端安裝證書
  • 從文件管理器中找到下載文件 => 如果是 .pem 結尾i,將後綴名改爲 .crt 並點擊該文件 => 輸入鎖屏密碼 => 等待證書導入後配置證書名(我填的是 Charles)即可。

實踐過程

選中目標網絡請求

從 Overview 中可以看到很全面抓包信息 。

使用斷點功能

1)、右鍵點擊要斷點的 URL,選中 BreakPoints 開啓斷點功能。
2)、點擊頂部 Proxy => Breadkpoint Settings。
3)、雙擊 Breakpoints Settings 面板中的目標

URL,在彈出的 Edit Breakpoint 面板中進行編輯。

4)、這裏默認選擇斷點 Request 與 Response,我們可以選擇僅斷點 Response 或 Request。點擊確認即斷點設置完成。
5)、然後,我們就可以點擊主面板右側的 Edit Response 編輯 Response,修改完成後點擊最下方的 Execute 即可。

使用 Map Local

1)、自由模擬服務端的返回數據,以提前進行接口測試。
1)、右鍵點擊要使用 Map Local 的 URL,選中Map Local 開啓斷點功能。
1)、然後,我們在 Edit Mapping 面板中選擇 Map To 的 Local path,選擇本地設定的 maplocal 本地數據(例如 JsonString)

弱網模擬功能

  • 1)、注意開啓前需將 Map Local 關閉。

  • 2)、點擊 Proxy => Throttle Setting => 選中 Enable Throttling

  • 3)、這裏預設了很多模擬設置,我們只需將 網絡包傳輸的速率 Throttle preset 設置爲較低的速率(一般設爲 256/512)。

碰到的問題

  • 1)、注意手機與筆記本電腦需要同一 WIFI 下,不能自己開熱點或使用公司內網,否則無法在 電腦端 無法彈出手機連接 Charles 的提示確認框,並且也無法下載 Charles 提供的 SSL 證書。
  • 2)、手機端下載 Charles 提供的 SSL 證書時最好不使用系統瀏覽器訪問。

3、Wireshark

強烈推薦 geektime-webprotocol

WireShark 主要可以用來對四種流進行跟蹤,如下所示:

  • TCP
  • UDP
  • SSL
  • HTTP

1)、WireShark 基本使用

如何捕獲報文

  • 1)、點擊捕獲->選項,打開捕獲窗口
    • 網卡設備/流量/捕獲過濾器,點擊“開始”按鈕開始抓包
    • 輸出(指定緩存文件)/選項(顯示、名稱解析、自動停止抓包條件) 面板
  • 2)、點擊捕獲->停止,停止抓包

Wireshark 面板

快捷方式工具欄

數據包的顏色(視圖->着色規則)

設定時間顯示格式

數據包列表面板的標記符號

文件操作

  • 1)、標記報文 Ctrl+M。
  • 2)、導出標記報文(文件->導出特定分組),亦可按過濾器導出報文 ,
  • 3)、合併讀入多個報文(文件->合併)。

如何快速抓取移動設備的報文?

  • 1、打開手機的 wifi 熱點。
  • 2、電腦連接手機的 wifi 熱點。
  • 3、用 Wireshark 打開捕獲->選項面板,選擇 wifi 熱點對應的接口設備抓包即可。

2)、Wireshark 過濾器

如果表達式的背景爲綠色,則說明過濾器的語法是正確的,紅色則說明有錯誤。

捕獲過濾器

它用於減少抓取的報文體積,使用 BPF(Berkeley Packet Filter) 語法,功能相對有限。

BPF 可以在設備驅動級別提供抓包過濾接口,多數抓包工具都支持此語法。而 BPF 的 Expression 表達式由多個 primitives 原語組成。而每一個 primitives 原語則由名稱或數字,以及描述它的多個 qualifiers 限定詞組成。

qualifiers 限定詞
  • 1、Type:設置數字或者名稱所指示類型
    • host、port。
    • net ,設定子網,net 192.168.0.0 mask 255.255.255.0 等價於 net 192.168.0.0/24。
    • portrange,設置端口範圍,例如 portrange 6000-8000。
  • 2、Dir:設置網絡出入方向
    • src、dst、src or dst、src and dst。
    • ra、ta、addr1、addr2、addr3、addr4(僅對 IEEE 802.11 Wireless LAN 有效)。
  • 3、Proto:指定協議類型
    • ether、fddi、tr、 wlan、
    • ip、 ip6、 arp、 rarp、
    • decnet、 tcp、udp、icmp、igmp、icmp
    • igrp、pim、ah、esp、vrrp
  • 4、其他
    • gateway:指明網關 IP 地址,等價於 ether host ehost and not host host。
    • broadcast:廣播報文,例如 ether broadcast 或者 ip broadcast。
    • multicast:多播報文,例如 ip multicast 或者 ip6 multicast。
    • less, greater:小於或者大於。

簡單示例

src or dst portrange 6000-8000 && tcp or ip6
複製代碼

顯示過濾器

它對已經抓取到的報文進行過濾顯示,功能強大。

基於協議域過濾
  • 捕獲所有 TCP 中的 RST 報文:tcp[13]&4==4。
  • 抓取 HTTP GET 報文:port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420。(47455420 是 ASCII 碼的 16 進制,表示”GET ”)
  • 抓取 HTTP POST 報文:port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354
顯示過濾器的過濾屬性

任何在報文細節面板中解析出的字段名,都可以作爲過濾屬性。在視圖->內部->支持的協議面板裏,可以看到各字段名對應的屬性名。例如,在報文細節面板中 TCP 協議頭中的 Source Port,對應着過濾屬性爲 tcp.srcport。

常用操作符
  • 1)、and(&&):AND 邏輯與,ip.src==10.0.0.5 and tcp.flags.fin。
  • 2)、or(||):OR 邏輯或,ip.scr==10.0.0.5 or ip.src==192.1.1.1。
  • 3)、xor(^^):XOR 邏輯異或,tr.dst[0:3] == 0.6.29 xor tr.src[0:3] == 0.6.29。
  • 4)、not(!):NOT 邏輯非,not llc。
  • 5)、[...​]:中括號[]Slice 切片操作符
    • [n:m]表示 n 是起始偏移量,m 是切片長度,例如:eth.src[0:3] == 00:00:83
    • [n-m]表示 n 是起始偏移量,m 是截止偏移量,例如:eth.src[1-2] == 00:83
    • [:m]表示從開始處至 m 截止偏移量,例如:eth.src[:4] == 00:00:83:00
    • [m:]表示 m 是起始偏移量,至字段結尾,例如:eth.src[4:] == 20:20
    • [m]表示取偏移量 m 處的字節,例如:eth.src[2] == 83
    • [,]使用逗號分隔時,允許以上方式同時出現,例如:eth.src[0:3,1-2,:4,4:,2] ==00:00:83:00:83:00:00:83:00:20:20:83
  • 6)、in:大括號{}集合操作符,例如 tcp.port in {443 4430..4434} ,實際等價於 tcp.port == 443 || (tcp.port >= 4430 && tcp.port ⇐ 4434)。
可用函數
  • upper:將字符串字段轉換爲大寫。
  • lower:將字符串字段轉換爲小寫。
  • len:返回字符串或字節數組的字節長度。
  • count:返回在一幀中字段出現的數量。
  • string:將非字符串字段轉換爲字符串。
顯示過濾器的可視化對話框
環形緩衝器

例如使用 3 個文件的環形緩存器,從 **.1 => **.2 => **.3 然後又從 **.1 文件開始記錄,形成環形。

4、TcpDump(網絡數據包嗅探器)

1)、抓包步驟

1、獲取 ROOT 權限的手機一部

2、下載 tcpdump

3、將 tcpdump 安裝到手機上

adb push tcpdump /data/local/tmp
複製代碼

4、修改 tcpdump 的權限,使其具有可執行的權限

chmod 777 /data/local/tmp/tcpdump
複製代碼

5、執行 tcpdump 命令進行抓包,按組合鍵 Ctrl + C 可以停止抓包

6、將抓到的數據包的信息保存爲 Pcap 文件,這裏僅需在執行 tcpdump 後加上 -w 參數

tcpdump-w /data/local/tmp/tcp.pcap
複製代碼

7、把 Pcap 複製到 電腦上,使用 Wireshark 分析數據包的流量。

2)、捕獲及停止條件

  • -D:列舉所有網卡設備。
  • -i:選擇網卡設備。
  • -c:抓取多少條報文。
  • --time-stamp-precision:指定捕獲時的時間精度,默認毫秒 micro,可選納秒 nano。
  • -s:指定每條報文的最大字節數,默認 262144 字節。

3)、文件操作

  • -w:輸出結果至文件(可被Wireshark讀取分析)。
  • -C:限制輸入文件的大小,超出後以後綴加 1 等數字的形式遞增。 注意單位是 1,000,000 字節。
  • -W:指定輸出文件的最大數量,到達後會重新覆寫第 1 個文件。
  • -G:指定每隔N秒就重新輸出至新文件,注意-w 參數應基於 strftime 參數指定文件名。
  • -r:讀取一個抓包文件。
  • -V:將待讀取的多個文件名寫入一個文件中,通過讀取該文件同時 讀取多個文件。

4)、輸出時間戳格式

  • -t:不顯示時間戳。
  • -tt:自1970年1月1日0點至今的秒數。
  • -ttt:顯示鄰近兩行報文間經過的秒數。
  • -tttt:帶日期的完整時間。
  • -ttttt:自第一個抓取的報文起經歷的秒數。

5)、分析信息詳情

  • -e:顯示數據鏈路層頭部。
  • -q:不顯示傳輸層信息。
  • -v:顯示網絡層頭部更多的信息,如 TTL、id 等。
  • -n:顯示 IP 地址、數字端口代替 hostname 等。
  • -S:TCP 信息以絕對序列號替代相對序列號。
  • -A:以 ASCII 方式顯示報文內容,適用 HTTP 分析。
  • -x:以 16 進制方式顯示報文內容,不顯示數據鏈路層。
  • -xx:以 16 進制方式顯示報文內容,顯示數據鏈路層。
  • -X:同時以 16 進制及 ACII 方式顯示報文內容,不顯示數據鏈路層 • -XX 同時以 16 進制及 ACII 方式顯示報文內容,顯示數據鏈路層。

5、Stetho

  • 1)、在 build.gradle 中,除了 Stetho 依賴外,還需添加 'com.facebook.stetho:stetho-okhttp3:1.5.0'。
  • 2)、在 Application 的 onCreate 方法中初始化 'Stetho.initializeWithDefaults(this)'。
  • 3)、調用 OkHttp 的 'addNeworkInterceptor' 方法添加 Stetho 用於收集網絡信息而提供的網絡攔截器。
  • 4)、訪問 Chrome 調試頁面 'chrome://inspect'。

6、其它的性能檢測工具

  • strace:跟蹤 Socket 相關的系統調用。
  • netstat:記錄多種網絡棧和接口統計信息。
  • ifconfig:記錄接口配置。
  • ip:記錄網絡接口統計信息。
  • ping:測試網絡連通性。
  • traceroute:測試網絡路由。
  • /proc/net 命令:查看網絡統計信息,Android TrafficState 使用了 /proc/net/xt_qtaguid/stats 和 /proc/net/xt_qtaguid/iface_stat_fmt 文件來統計 App 的流量信息。

三、精準獲取流量消耗

1、如何判斷 App 流量消耗偏高?

  • 1)、絕對值看不出高低。
  • 2)、對比競品,相同 Case 對比流浪消耗。
  • 3)、異常監控超過正常指標。

2、測試方案

  • 1)、打開手機設置 => 流量管理 => 僅允許目標 App 聯網
  • 2)、可以查找出大多數的問題,但是線上場景線下可能遇不到。

3、線上流量獲取方案

1)、TrafficStats

特點

  • API 18 以上。
  • 記錄手機重啓以來的數據流量。

API

  • getMobileRxBytes():通過蜂窩流量接收到的信息。
  • getUidRxBytes(int uid):獲取指定 uid 的接收流量。
  • getTotalRxBytes():總髮送流量。

缺點

無法獲取某個時間段內的流量消耗。

2)、NetworkStatsManager

API 23 之後。

特點

  • 1)、獲取指定時間間隔內的流量信息。
  • 2)、獲取不同網絡類型下的消耗。

NetUtils.getStats

獲取指定時間間隔的 蜂窩 + WIFI 流量總信息

4、前後臺流量獲取方案

問題:線上反饋 App 後臺流量消耗大?

只獲取一個時間段的流量不夠全面。

實現原理

後臺定時任務 => 獲取時間間隔內流量 => 記錄前後臺 => 分別計算 => 上報 APM 後臺 => 流量治理依據

小結

  • 1)、該方案無法獲取應用在前後臺切換時的流量,因此有一定的誤差,但這個誤差是可以接受的。
  • 2)、結合精細化的流量異常報警針對性的解決後臺跑流量的問題。

成功 log 如下所示:

2020-05-11 10:47:55.633 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 193 | lambda$initEventAndData$1$MainActivity] backNetUseData: 4 MB
2020-05-11 10:47:55.646 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 194 | lambda$initEventAndData$1$MainActivity] foreNetUseData: 4 MB
2020-05-11 10:47:55.652 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 197 | lambda$initEventAndData$1$MainActivity] totalNetUseData: 8 MB
複製代碼

四、網絡請求流量優化

1、常見使用網絡的場景

1)、數據壓縮

POST 請求 Body 使用 GZip 壓縮,同時服務端返回 Body 也使用 GZip 壓縮。

2)、圖片

  • 圖片上傳前壓縮。
  • 圖片使用策略細化:讓 服務端/CDN 雲服務器 優先使用縮略圖/WebP格式圖片。

3)、性能日誌上報:批量 + 特定場景上報

APM 相關、單點問題相關。例如埋點數據可以等到某一時機點(例如 開啓了 WIFI、數據量過大必須上傳一部分時)再上傳。

4)、數據緩存

服務端返回加上過期時間,避免每次重新獲取。 節約流量且大幅提高數據訪問速度,更好的用戶體驗。

Request 緩存設置

  • 1、Pragma:no-cache:去服務器拉取最新的資源,不使用緩存。
  • 2、If-Modified-Since:datetime:如果資源在客戶端提供的時間後發生改變,服務器會返回新的資源,否則使用緩存。
  • 3、If-None-Match:etagvalue:如果資源的標識和服務器的不同,返回新的資源。

當 Request 的頭部是 2 和 3 時,如果服務器的資源沒有修改,則服務器會返回 HTTP/304 Not Modified,客戶端會使用緩存的 Response。

Response 緩存設置

HTTP Response 是否可以緩存是由 Response 的頭部控制的,服務器可以通過 Expires 和 Cache-Control 控制 Response 如何在客戶端緩存。

Expires

Expires 頭部會包含一個日期,即該資源緩存的有效期,客戶端有新的相同請求時,如果資源緩存沒有過期,則使用緩存資源,服務器不會返回任何東西。

Cache-Control

Cache-Control 可以標明 Response 如何存儲及其如何使用,其選項如下所示:

  • 1)、public:Response 可以存儲在任何 Cache 中,包括共享的 Cache。
  • 2)、private:Response 存儲在私有 Cache 中,只能被一個用戶使用。
  • 3)、no-cache:Response 將來不會被使用。
  • 4)、no-store:Response 將來不會被使用,也不會寫到磁盤上。
  • 5)、max-age=#seconds:Response 在設定的時間內可以被重複使用。
  • 6)、must-revalidate:和原始服務器確認 Response 是最新後,可以使用緩存。

OKHttp 無網數據緩存實現

POST 在 OKHttp 中默認不會緩存,因爲 POST 一般是用來修改數據的。在 Awesome-WanAndroid 中的 HttpModule—cacheInterceptor 中就已經實現了 OKHttp 的無網數據緩存,代碼如下所示:

File cacheFile = new File(Constants.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = chain -> {
    Request request = chain.request();
    if (!CommonUtils.isNetworkConnected()) {
        // 無網時強制使用數據緩存,以提升用戶體驗。
        request = request.newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .build();
    }
    Response response = chain.proceed(request);
    if (CommonUtils.isNetworkConnected()) {
        int maxAge = 0;
        // 有網絡時, 不緩存, 最大保存時長爲0
        response.newBuilder()
                .header("Cache-Control", "public, max-age=" + maxAge)
                .removeHeader("Pragma")
                .build();
    } else {
        // 無網絡時,設置超時爲4周
        int maxStale = 60 * 60 * 24 * 28;
        response.newBuilder()
                .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                .removeHeader("Pragma")
                .build();
    }
    return response;
};
// 緩存優化
builder.addNetworkInterceptor(cacheInterceptor);
builder.addInterceptor(cacheInterceptor);
builder.cache(cache);
複製代碼

5)、離線包、增量數據更新

加上版本的概念,僅傳輸有變化的數據。

6)、請求頭壓縮

如果請求頭不變,服務端可以使用映射緩存 請求頭 MD5 : 請求頭,之後請求頭都使用 MD5 即可。

7)、優化發送頻率和時機

8)、合併網絡請求、減少請求次數。

9)、流量兜底能力

如果發現流量異常,我們可以通過後臺服務器終止協議交互,以避免問題惡化。

2、流量統計

我們可以利用 network-connection-class 進行流量統計,它內部使用的是 API 8 的 TrafficStats 類,用於獲取整個手機或者某個 UID 從開機算起的網絡流量。

1)、四個核心 API

// 從開機開始Mobile網絡接收的字節總數,不包括Wifi
getMobileRxBytes()        
// 從開機開始所有網絡接收的字節總數,包括Wifi
getTotalRxBytes()     
// 從開機開始Mobile網絡發送的字節總數,不包括Wifi
getMobileTxBytes()        
// 從開機開始所有網絡發送的字節總數,包括Wifi
getTotalTxBytes()         
複製代碼

2)、對應的Linux 內核 proc 統計接口

// stats接口提供各個uid在各個網絡接口(wlan0, ppp0等)的流量信息
/proc/net/xt_qtaguid/stats
// iface_stat_fmt接口提供各個接口的彙總流量信息
proc/net/xt_qtaguid/iface_stat_fmt
複製代碼

3)、工作原理

  • 1)、讀取 proc,並將目標 UID 下面所有網絡接口的流量相加。
  • 2)、Android 7.0 之後只能通過 TrafficStats 拿到自己應用的流量信息。

《深入探索 Android 性能優化(三、網絡優化篇)下》將在本週四發佈,敬請期待。

公衆號

我的公衆號 JsonChao 開通啦,如果想第一時間(明天8:30)查看《深入探索 Android 性能優化(三、網絡優化篇)下》,歡迎掃描二維碼進行閱讀~

參考鏈接:


Contanct Me

● 微信:

歡迎關注我的微信:bcce5360

● 微信羣:

由於微信羣人數過多,麻煩大家想進微信羣的朋友們,加我微信拉你進羣。

● QQ羣:

2千人QQ羣,Awesome-Android學習交流羣,QQ羣號:959936182, 歡迎大家加入~

About me

很感謝您閱讀這篇文章,希望您能將它分享給您的朋友或技術羣,這對我意義重大。

希望我們能成爲朋友,在 Github掘金上一起分享知識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章