深入探索Android網絡優化

目錄

寫在前面

一、網絡優化維度

二、網絡優化工具選擇

2.1、Network Profiler

2.2、抓包工具

2.3、Stetho

三、精準獲取流量消耗

3.1、如何判斷APP流量消耗偏高

3.2、線上流量獲取方案

3.3、前後臺流量獲取方案

四、網絡請求流量優化

4.1、需要使用網絡的場景

4.2、網絡請求優化手段

五、網絡請求質量優化

5.1、HTTPDNS

5.2、協議版本升級

5.3、網絡請求質量監控

5.4、網絡容災機制

5.5、其它優化

六、網絡體系化方案建設


寫在前面

獨在異鄉爲異客,每逢佳節胖三斤!😜

不知不覺間端午小長假已經結束了,各位小夥伴們假期過的還好嗎?又到了新的工作日了,都收收心吧,開始好好工作啦!努力工作,認真生活,不辜負你的每一天!上一篇中說到了Android的線程優化——《Android線程優化你瞭解多少》,今天繼續Android性能優化系列專題的學習,來說說Android中的網絡優化。

一、網絡優化維度

①、流量消耗

  • 對於用戶要儘可能的做到一段時間內流量消耗的精準度量,而且還要能夠知道用戶不同網絡類型及前後臺流量消耗情況
  • 監控相關:用戶流量消耗均值、異常率(一定時間內流量消耗多網絡請求次數多下載文件過大
  • 完整鏈路全部監控(每個請求的Request、Response相關的所有信息全部記錄),服務端下發指令控制本地上傳,客戶端在超過閾值之後主動上報

②、網絡請求質量

  • 用戶體驗:請求速度、成功率(直接影響到用戶體驗)
  • 監控相關:請求時長、業務成功率、失敗率、Top失敗接口(詳細分析發現問題)

③、其它維度

  • 公司成本:帶寬、服務器數、CDN等方面的開支
  • 網絡請求密集對手機耗電量也有一定影響

④、網絡優化誤區

  • 只關注流量消耗,忽視其它維度,往往導致我們做的網絡優化不夠全面
  • 只關注均值、用戶整體數據,忽略個體數據

二、網絡優化工具選擇

2.1、Network Profiler

它是Android Studio自帶的工具:

  • 顯示實時網絡活動:網絡請求發送、接收數據及連接數
  • 需要啓用高級分析:這些功能Android Studio並沒有默認全部開放,需手動啓用高級分析
  • 只支持HttpURLConnection和OkHttp網絡庫

首先我們打開Android Studio,然後在菜單欄選擇Run--->Edit Configurations--->Android App--->app--->profiling,然後如下圖勾選第一個Enable advanced profiling選項,點擊APPLY--->OK即可:

然後進入Network Profiler的視圖,此時我發送一條網絡請求,然後時間線上就會顯示出來這條請求,現在我選中這條請求的一個時間範圍,然後下方就會顯示出這條請求的名稱、大小、類型、狀態、時間等,右側會有這條請求的詳細信息,你可以預覽數據,我這裏的是一個接口請求,如果有圖片請求右側預覽界面也可以預覽圖片:

2.2、抓包工具

  • Charles:使用Java開發,跨平臺,Mac上使用的比較多
  • Fiddler:使用C#開發,Windows上使用的比較多
  • Wireshark:非常流行的網絡封包分析軟件,功能強大,可以截取各種網絡封包,顯示網絡封包的詳細信息,一般需要了解網絡協議
  • TcpDump:Linux中強大的網絡數據採集分析工具

下面是我使用Charles抓包工具抓包的一張截圖,手機和電腦的網絡保持一致,並且手動修改代理地址爲電腦ip,然後就可以抓包了,具體的工具的使用方法就不過多介紹了,網上一搜一大把,主要功能大家可以去搜一點breakpoint斷點功能,通過斷點可以手動修改請求,map local可以本地模擬數據加快開發進度以及補充測試時模擬服務端各種髒數據情況,Throttle可以進行弱網環境下的場景模擬,大家可以具體的去了解一下,由於篇幅原因就不再多說了,畢竟工具的使用需要自己實際體驗:

2.3、Stetho

  • 強大的應用調試橋,連接Android和Chrome
  • 網絡監控、視圖查看、數據庫查看、命令行擴展等

使用方式:

  • 添加依賴:implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
  • 初始化:Stetho.initializeWithDefaults(this);
  • 添加攔截器:addNetworkInterceptor
  • Chrome瀏覽器:chrome://inspect

實際使用的話你會發現它和Network Profiler有點像,一般也很少會使用它去做抓包工具,所以關於它的實際用法只是簡單的提一下,具體的有感興趣的可以實際操作一下,

首先添加依賴並初始化,都是上面的步驟:

Stetho.initializeWithDefaults(this);

然後添加攔截器:

最後在Chrome瀏覽器(注意必須是Chrome瀏覽器)中輸入chrome://inspect之後按照下圖中框選出的位置點擊即可開始抓包,這裏可能會需要翻牆,因爲我實際測試的時候發現不翻牆是報404的:

三、精準獲取流量消耗

3.1、如何判斷APP流量消耗偏高

這個問題決定了我們什麼時候開始對流量進行優化,這裏就簡單說一下答案:

  • 絕對值看不出高低:流量的絕對值看不出高低,比如經過測試,我們的APP消耗了20MB的流量,但是它並不是說我們就需要立馬優化它,因爲你這個流量消耗可能是基於連續使用了APP很長時間的場景下消耗的,所以絕對值不能作爲流量是否偏高的唯一統計標準
  • 對比競品,相同場景對比流量消耗:比如用我們的APP和競品APP在相同的網絡環境下同時去跑一個相同功能的流程,保證其他因素都相同,變量唯一,如果我們的APP和競品的流量消耗差距較大,那麼我們肯定要考慮做流量優化了,絕對值和競品對比二者應該結合使用
  • 異常監控超過正常指標:比如設定用戶使用某個功能單次消耗流量的值爲X,如果上線之後超過了預期值,這種情況就需要確認一下流量消耗是否是偏高的

流量測試方案:

  • 設置——流量管理
  • 抓包工具:只允許本App聯網
  • 可以解決大多數問題,但是線上場景線下可能遇不到

當你的APP到了穩定期之後,日活可能會有成百上千萬甚至更多,此時APP的功能應該是非常複雜的,並且還具備了其他的一些功能比如說監控,這些功能的網絡請求並不是實時上報的,因此做流量消耗的週期應該會很長,不是簡單的十幾二十分鐘就能搞定的。另外,我們還應該排除別的APP的干擾,比如你想要抓取你的APP的所有網絡請求,此時應該打開設置界面進入流量管理,設置只允許你的這個APP可以聯網,別的所有APP的聯網功能全都關閉,這樣使用抓包工具抓到的請求都是這個APP的請求了。這種抓包方案在線下測試一般都是沒有問題的,但是某些場景可能會在線上出現,在線下就很難發現,所以這些場景就只能通過線上監控才能發現。

3.2、線上流量獲取方案

①、TrafficStats

  • API8以上版本提供的流量數據統計方案:它統計到的數據是手機上次重啓之後的流量消耗
  • getUidRxBytes(int uid)指定Uid的接收流量
  • getTotalTxBytes()總共發送的流量

這種方案其實不推薦使用,所以就不多說了,有興趣的朋友可以自己嘗試一下,直接調用它的靜態方法就可以獲取了:

//手機通過蜂窩流量接收到的流量信息
TrafficStats.getMobileRxBytes();

存在的問題:

  • 無法獲取某個時間段內的流量消耗,只能獲取一個大的具體值

②、NetworkStatsManager

  • API23之後的流量統計
  • 可以獲取指定時間間隔內的流量信息
  • 可以獲取不同網絡類型下的流量消耗

接下來我們通過實戰來統計這個Demo本月消耗的蜂窩流量情況:

public void getNetStats() {
        //保護性操作
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return;
        }
        long netDataReceive = 0; //接收的流量
        long netDataSend = 0; //發送的流量
        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        @SuppressLint("MissingPermission")
        String subId = telephonyManager.getSubscriberId(); //此處需要權限,獲取的是SIM卡唯一標識
        //系統服務通過getSystemService方法拿到
        NetworkStatsManager manager = (NetworkStatsManager) getSystemService(Context.NETWORK_STATS_SERVICE);
        NetworkStats networkStats = null;
        NetworkStats.Bucket bucket = new NetworkStats.Bucket(); //離散時間桶
        try {
            //參數分別是:網絡類型、SIM卡唯一標識、開始時間、結束時間
            networkStats = manager.querySummary(NetworkCapabilities.TRANSPORT_CELLULAR, subId, getStartTime(), System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
        //遍歷時間桶
        while (networkStats != null && networkStats.hasNextBucket()) {
            networkStats.getNextBucket(bucket);
            int uid = bucket.getUid();
            if (getAppUid() == uid) {
                netDataReceive += bucket.getRxBytes();
                netDataSend += bucket.getTxBytes();
            }
        }
        LogUtils.i("anqinetuse------>" + (netDataSend + netDataReceive));
    }

    private static volatile int sUId = -1;

    //通過包名獲取uid
    private int getAppUid() {
        if (sUId == -1) {
            PackageManager packageManager = getPackageManager();
            try {
                PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_META_DATA);
                if (packageInfo != null) {
                    sUId = packageInfo.applicationInfo.uid;
                }
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        return sUId;
    }

後續可以將這個獲取流量的方法進一步封裝,比如將它封裝到基礎庫中,然後通過入參網絡類型、開始時間、結束時間等在應用層調用,更加方便靈活的獲取你想要的數據。我們將獲取到的結果進行打印輸出:

可以看到這個值是292886,將這個除以1024得到的是286KB,然後到手機設置裏面找到數據流量排行,選擇本月,找到這個Demo看一下系統統計出來的流量消耗是多少:

經過對比發現兩個值還是相當接近的,說明我們通過代碼統計到的數據應該是很精確的一個值了,所以今後我們就可以統計出線上用戶流量消耗的準確值了,如果今後有用戶反饋說某一天流量消耗的比較多,我們就可以通過APM後臺下發一條指令來回撈一下用戶當天具體的流量消耗值,結合用戶使用時長,就可以分析出用戶的流量消耗是否存在異常。

3.3、前後臺流量獲取方案

場景:線上反饋App後臺跑流量

很多用戶對後臺流量非常關心,大多數用戶都是非常害怕你的應用在後臺一直跑流量的,如果你只是使用上面講到的這種方案,實際上我們並不知道消耗的這些流量前後臺所佔用的比例,所以只獲取一個時間段的值不夠全面,還需要知道這些流量到底是在前臺消耗的還是在後臺消耗的。

解決方案:

App啓動時執行一個後臺任務,這個後臺任務每隔一段時間獲取一下這段時間內的流量消耗,自己維護一份數據的統計,分別記錄用戶在前後臺的流量消耗總量,結合別的監控在合適的時間上報到APM後臺作爲流量治理的依據,這樣當用戶反饋時,我們可以直接查看用戶流量消耗統計,然後判斷是否存在問題,這種方案可以結合上面的代碼來實現,下面說一下實現思路:

首先將上面的代碼封裝一下,將開始時間和結束時間作爲參數從調用方傳遞:

public long getNetStats(long startTime,long endTime) {
    ......//省略代碼
    return (netDataSend + netDataReceive);
}

其次可以監聽app處於前臺還是後臺,可以使用標誌位進行判定,具體的監聽方法可以直接使用下面這種方式:

getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            ......//省略部分代碼
            @Override
            public void onActivityResumed(@NonNull Activity activity) {
                //處於前臺
            }

            @Override
            public void onActivityPaused(@NonNull Activity activity) {
                //進入後臺
            }
            ......//省略部分代碼
        });

然後再開啓一個定時任務,每隔一段時間獲取一次流量消耗情況:

Executors.newScheduledThreadPool(1).schedule(new Runnable() {
            @Override
            public void run() {
                long useNum = getNetStats(System.currentTimeMillis()-30*1000,System.currentTimeMillis());
                //前臺還是後臺
            }
        },30, TimeUnit.SECONDS);

總結:

  • 有一定誤差,在可接受範圍內:注意我們這裏統計的是當時的一段時間內的流量消耗情況,在這段時間內用戶有可能是在前後臺切換的,所以它肯定會存在一定的誤差
  • 結合精細化的流量異常報警針對性的解決後臺跑流量

四、網絡請求流量優化

4.1、需要使用網絡的場景

  • 數據:Api請求、資源包(app的升級包、H5的zip包、RN的bundle包)、配置信息(A/BTest等)
  • 圖片:下載、上傳(流量消耗大戶)
  • 監控:APM相關、單點問題相關

4.2、網絡請求優化手段

①、數據緩存

  • 服務端返回加上過期時間,避免每次重新獲取
  • 節約流量且大幅提高數據訪問速度,更好的提升用戶體驗
  • OkHttp、Volly都有比較好的緩存實踐

首先來寫一個針對無網絡情況下的攔截器NoNetInterceptor,策略模式設置爲沒有網絡時強制開啓緩存:

public class NoNetInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Request.Builder builder = request.newBuilder();
        if(!Utils.isNetworkConnected(BaseApp.getApplication())){
            //沒有網絡時強制開啓緩存
            builder.cacheControl(CacheControl.FORCE_CACHE);
        }
        return chain.proceed(builder.build());
    }
}

然後在OkHttp中添加緩存:

就這兩步就搞定了哦,然後來對比一下結果,沒有緩存時關掉網絡應用進去就是個空白頁,有緩存的話即使關掉網絡也是有數據能夠展示的,給人一種好的用戶體驗:

②、增量數據更新

  • 加上版本的概念,只傳輸有變化的數據
  • 配置信息

舉個栗子:省市區等數據更新,這種類型的數據並不是經常變化的,如果每次都全量更新很明顯造成了浪費,所以可以只更新有變化的那部分數據,這個場景需要和服務端實際配合,所以這裏就不演示了,不過我相信大家也都明白是什麼意思了。

③、數據壓縮

  • Post請求Body使用GZip壓縮:請求時帶上GZip請求頭,服務端返回時也帶上GZip壓縮,這樣數據流就是被壓縮過的
  • 請求頭壓縮:請求頭也是需要佔用一定的體積的,假設請求頭不變的話可以只傳遞一次,以後都值傳遞上一次請求的MD5值,服務端作緩存對於需要的信息直接從緩存中獲取
  • 圖片上傳之前必須壓縮:避免圖片原圖上傳,這裏推薦使用魯班(圖片壓縮庫)這個庫,爲什麼推薦它呢,因爲它是號稱最接近微信朋友圈的圖片壓縮算法,GitHub上的star數也是相當高了11.8K

下面來實際使用一下魯班這個圖片壓縮庫,看一下圖片大小的前後對比情況,首先我在手機的外置存儲卡上面準備了一張圖片:/storage/emulated/0/Android/luban/yingbao.png,圖片大小是2.55MB,然後在代碼中進行壓縮,壓縮完了之後還存儲在luban這個文件夾下:

Luban.with(MainActivity.this)
                        .load(Environment.getExternalStorageDirectory().getPath()+"/Android/luban/yingbao.png")
                        .setTargetDir(Environment.getExternalStorageDirectory().getPath()+"/Android/luban")
                        .launch();

OK,這樣一行代碼就壓縮完了,我們來看看壓縮之後的大小和壓縮質量的對比,如下圖所示:從2.55MB壓縮到了40KB,極大的減小了圖片的體積,並且通過右側兩張圖片放大後的效果可以看到圖片的質量幾乎看不出來有什麼差別:

所以圖片壓縮在使用過程中是相當重要的,一般情況下我們都要避免圖片的原圖上傳。

④、優化發送頻率和時機

  • 合併網絡請求,減少請求次數:每個網絡請求時都會有冗餘信息,比如請求頭,合併網絡請求可以減少冗餘信息的傳遞
  • 性能日誌上報:批量+特定場景上報。對於成熟項目來說,會有很多性能日誌埋點,這些數據最好不要在每次記錄的時候都上傳,而是記錄的時候就只記錄,在合適的時間點,比如用戶處於WIFI環境下再去上傳,這樣對於用戶的流量沒有太大影響

⑤、圖片相關

  • 圖片使用策略優化:比如在列表展示時優先使用縮略圖,直接展示原圖只是擴大了內存的消耗並沒有任何實際的意義
  • 使用WebP格式圖片:在不改變圖片尺寸的情況下可以有效的降低圖片的物理體積,這個需要結合實際情況進行選擇,因爲可能實際使用的雲服務並沒有直接將jpg轉換爲webp的能力

縮略圖:原圖是32KB,生成的縮略圖是6KB,大小有效減小了將近5倍多,並且針對於手機列表仍然是可以進行展示的,所以使用縮略圖可以有效降低流量的消耗

WebP:使用這種圖片格式對於圖片尺寸沒有任何變化,但是圖片大小也可以有效降低:

五、網絡請求質量優化

上一部分我們說了網絡請求的流量優化,實際上對用戶體驗影響最大的是網絡請求質量很差,這一點也是讓人容易忽略的一個地方,我們開發測試階段基本上都是在公司的wifi環境下進行的,網絡環境一般都還是OK的。但是實際上線之後用戶的網絡環境我們是不可控的,假設有用戶經常反饋界面打不開或者是打開較慢,圖片加載不出來等情況,這些對用戶的使用體驗是有巨大影響的,很多情況下用戶就會拋棄我們的APP,轉而去尋求同類型下體驗更好的APP,所以網絡請求質量尤爲關鍵。總的來說質量指標就是以下兩點:

  • 網絡請求成功率
  • 網絡請求速度

5.1、HTTPDNS

在介紹質量優化之前,先來說說Http請求的過程:

  • 首先開始請求,請求到達運營商的Dns服務器並解析成對應的IP地址
  • 創建連接,開始TCP三次握手,然後根據IP地址找到相應的服務器,發起一個請求
  • 服務器找到對應的資源原路返回給訪問的用戶

從上面介紹的請求的過程不難發現網絡請求的成功率和速度一開始就受到DNS解析服務的影響,如果域名到IP地址這個過程被劫持、或者解析速度較慢都會嚴重影響用戶體驗,DNS被劫持就是用戶得到的數據並不是真實想要提供給用戶的數據,解析比較慢則會造成用戶等待的時間比較長,所以DNS優化是網絡請求質量優化的第一步。

  • 解決方案:使用HTTPDNS,繞過運營商域名解析過程(它不是使用傳統的DNS協議向DNS服務器的53端口發送請求,而是使用Http協議向DNS服務器的80端口發送請求)
  • 優勢:降低平均訪問時長(節省了一次解析過程)、提高連接成功率(降低LocalDNS的劫持,繞過運營商的域名解析過程)

實戰OkHttp結合HTTPDNS的使用:

首先引入一個庫:HTTPDNS是阿里雲面向移動開發者提供的移動端DNS解析服務。通過該SDK,開發者可以在自己的Android APP中獲得可靠、實時、精準的DNS解析服務,徹底解決傳統DNS面臨的域名劫持、解析時延長、調度不精準等問題,官方文檔地址:https://help.aliyun.com/document_detail/150879.html

implementation ('com.aliyun.ams:alicloud-android-httpdns:1.1.7@aar') {
    transitive true
}

接着來創建一個集合OkHttp使用的DNS解析服務的類,此類使用單例模式:

public class OkHttpDNS implements Dns {
    //阿里雲提供的HttpDns解析服務
    private HttpDnsService dnsService;

    //單例模式
    private static OkHttpDNS instance = null;

    private OkHttpDNS(Context context) {
        dnsService = HttpDns.getService(context, ""); //用戶id這裏演示直接寫的""
    }

    public static OkHttpDNS getIns(Context context) {
        if (instance == null) {
            synchronized (OkHttpDNS.class) {
                if (instance == null) {
                    instance = new OkHttpDNS(context);
                }
            }
        }
        return instance;
    }

    @Override
    public List<InetAddress> lookup(String hostname) throws UnknownHostException {
        //優先使用阿里雲dns解析服務返回的ip地址,如果爲空再走系統的DNS解析服務
        String ip = dnsService.getIpByHostAsync(hostname);
        if(ip != null){ //如果不爲空直接使用這個ip進行網絡請求
            List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));
            return inetAddresses;
        }
        return Dns.SYSTEM.lookup(hostname); //如果爲空走系統的解析服務
    }
}

最後在OkHttp中設置自己的DNS解析服務:

這樣在網絡請求的時候就可以繞過系統DNS解析這一步來提升網絡請求的質量。

5.2、協議版本升級

接着來說說HTTP協議版本的優化,上面在介紹HTTP請求的時候其中有一步是是創建連接,這裏面會出現TCP的三次握手,這個時間是比較長的,如果每次網絡請求都走三次握手,很明顯效率是非常低的,所以HTTP的不同版本對這一點的優化也是非常多的,下面來看下HTTP協議不同版本之間的主要區別:

  • 1.0版本:TCP連接不復用——相對較老,現在基本上沒有使用此版本的服務了,它的TCP是不復用的,每個TCP連接只能發送一個請求,如果需要再次請求別的資源就需要重新建立一個連接,TCP創建連接的成本很高,需要三次握手,並且開始階段發送速度較慢,因此這個版本性能非常差
  • 1.1版本:引入持久連接,但數據通訊按次序進行——此版本開始,TCP連接默認不關閉,多個網絡請求可以複用,效率得到了保證,但是同一個TCP連接裏面所有的數據通信必須按照次序來,處理完一個請求之後再響應下一個請求,如果前面的網絡請求比較慢那麼後面的就需要等待
  • 2.0版本:多工,客戶端、服務器雙向實時通信——二進制協議,它有一個非常大的好處是多工,默認實現了連接複用,客戶端和服務端可以同時發送多個請求和迴應,實現了雙向的實時通信

如果有條件的情況下,儘量選擇高版本的HTTP協議。

5.3、網絡請求質量監控

  • 接口請求耗時、成功率、錯誤碼——實際上這個耗時和成功率服務端也能統計,但是服務端拿到的數據並不完整,因爲實際業務場景下有些請求可能並沒有到達服務端就已經失敗了,這種場景下服務端肯定無法統計這些請求,並且服務端傳回的數據加上網絡通道的延遲時間肯定要比統計到的時間要長,所以必須在客戶端也加上統計
  • 圖片加載的每一步耗時

①、OkHttp如何獲取網絡請求的質量數據

OkHttp給我們留了一個回調,叫做EventListener,我們可以自己實現一個EventListener,然後設置給每一次的網絡請求:

首先創建一個model並且定義幾個成員變量作爲統計的對象:

public class OkHttpEvent {
    public long dnsStartTime; //dns開始時間
    public long dnsEndTime; //dns結束時間
    public long responseBodySize; //網絡請求返回值大小
    public boolean apiSuccess; //網絡請求是否成功
    public String errorReason; //請求失敗的具體原因
}

然後自定義一個OkHttpEventListener,並且實現它的回調方法,每次創建OkHttpEventListener的時候就創建出一個OkHttpEvent,在具體的回調方法中爲其賦值:

public class OkHttpEventListener extends EventListener {

    public static final Factory FACTORY = new Factory() {
        @Override
        public EventListener create(Call call) {
            return new OkHttpEventListener();
        }
    };

    OkHttpEvent okHttpEvent;
    public OkHttpEventListener() {
        super();
        okHttpEvent = new OkHttpEvent();
    }

    @Override
    public void callStart(Call call) {
        super.callStart(call);
        Log.i("Jarchie","callStart");
    }

    @Override
    public void dnsStart(Call call, String domainName) {
        super.dnsStart(call, domainName);
        okHttpEvent.dnsStartTime = System.currentTimeMillis();
    }

    @Override
    public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
        super.dnsEnd(call, domainName, inetAddressList);
        okHttpEvent.dnsEndTime = System.currentTimeMillis();
    }

    @Override
    public void responseBodyEnd(Call call, long byteCount) {
        super.responseBodyEnd(call, byteCount);
        //網絡請求返回值的大小,此處統計網絡請求的流量消耗,所以此處可做流量預警
        okHttpEvent.responseBodySize = byteCount;
    }

    @Override
    public void callEnd(Call call) {
        super.callEnd(call);
        okHttpEvent.apiSuccess = true;
    }

    @Override
    public void callFailed(Call call, IOException ioe) {
        Log.i("Jarchie","callFailed");
        super.callFailed(call, ioe);
        okHttpEvent.apiSuccess = false;
        okHttpEvent.errorReason = Log.getStackTraceString(ioe);
        Log.i("Jarchie","reason "+okHttpEvent.errorReason);
    }
}

最後在OkHttp中進行設置:

通過上面的方法我們就可以拿到這次網絡請求的每一步中包括dns解析的時間、request&response的時間、字節數等信息,這些數據都是做線上監控所必需的。

②、如何監聽圖片加載進度

關於圖片加載現在大家也都是使用開源的解決方案,比較多的是Glide和Fresco了,我們需要做的是監聽圖片加載的整個過程,然後就可以計算出來每一步的耗時情況了,所以核心的是如何監聽圖片加載的全流程?這裏具體的解決方案我就不再詳細寫了,下面把對應的鏈接提供給大家,直接點擊查看詳細的實現過程吧:

5.4、網絡容災機制

  • 備用服務器分流
  • 多次失敗後一定時間內不進行請求,避免雪崩效應

5.5、其它優化

  • 資本層面:CDN加速、提高帶寬、動靜資源分離(更新後清理緩存)
  • 減少傳輸量,注意請求時機及頻率
  • OkHttp的請求池:當前正在執行網絡請求的任務數的最大值默認是64,單個Host可以同時運行5個網絡請求,這樣做可以防止某個域名的請求過多其它的域名請求沒有機會執行

六、網絡體系化方案建設

線下測試

  • 方案:只抓單獨App,將其餘App的聯網權限全部關閉
  • 側重點:請求有誤、多餘,網絡切換、弱網、無網測試

線上監控分爲兩個部分:服務端監控和客戶端監控

服務端監控

  • 請求耗時(區分地域、時間段、版本、機型)
  • 失敗率(業務失敗與請求失敗)
  • 排名靠前的失敗接口、異常接口

客戶端監控

  • 接口的每一步詳細信息(DNS、連接、請求等)
  • 請求次數、網絡包大小、失敗原因
  • 圖片監控

異常監控體系

  • 服務器防刷:超限拒絕訪問
  • 客戶端:大文件預警、異常兜底策略(連續多次請求失敗暫停訪問並加大重試時長)
  • 單點問題追查

OK,關於Android網絡優化相關的介紹,就是上面這些了,那今天就先寫到這裏吧,各位小夥伴們,咱們下期再會!

祝:工作順利!

Demo地址:https://github.com/JArchie/PerformanceOptimizeProject

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