深入探索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网络优化_第1张图片

独在异乡为异客,每逢佳节胖三斤!

不知不觉间端午小长假已经结束了,各位小伙伴们假期过的还好吗?又到了新的工作日了,都收收心吧,开始好好工作啦!努力工作,认真生活,不辜负你的每一天!上一篇中说到了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即可:

深入探索Android网络优化_第2张图片

然后进入Network Profiler的视图,此时我发送一条网络请求,然后时间线上就会显示出来这条请求,现在我选中这条请求的一个时间范围,然后下方就会显示出这条请求的名称、大小、类型、状态、时间等,右侧会有这条请求的详细信息,你可以预览数据,我这里的是一个接口请求,如果有图片请求右侧预览界面也可以预览图片:

深入探索Android网络优化_第3张图片

2.2、抓包工具

  • Charles:使用Java开发,跨平台,Mac上使用的比较多
  • Fiddler:使用C#开发,Windows上使用的比较多
  • Wireshark:非常流行的网络封包分析软件,功能强大,可以截取各种网络封包,显示网络封包的详细信息,一般需要了解网络协议
  • TcpDump:Linux中强大的网络数据采集分析工具

下面是我使用Charles抓包工具抓包的一张截图,手机和电脑的网络保持一致,并且手动修改代理地址为电脑ip,然后就可以抓包了,具体的工具的使用方法就不过多介绍了,网上一搜一大把,主要功能大家可以去搜一点breakpoint断点功能,通过断点可以手动修改请求,map local可以本地模拟数据加快开发进度以及补充测试时模拟服务端各种脏数据情况,Throttle可以进行弱网环境下的场景模拟,大家可以具体的去了解一下,由于篇幅原因就不再多说了,毕竟工具的使用需要自己实际体验:

深入探索Android网络优化_第4张图片深入探索Android网络优化_第5张图片

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);

然后添加拦截器:

深入探索Android网络优化_第6张图片

最后在Chrome浏览器(注意必须是Chrome浏览器)中输入chrome://inspect之后按照下图中框选出的位置点击即可开始抓包,这里可能会需要,因为我实际测试的时候发现不是报404的:

深入探索Android网络优化_第7张图片

三、精准获取流量消耗

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看一下系统统计出来的流量消耗是多少:

深入探索Android网络优化_第8张图片深入探索Android网络优化_第9张图片

经过对比发现两个值还是相当接近的,说明我们通过代码统计到的数据应该是很精确的一个值了,所以今后我们就可以统计出线上用户流量消耗的准确值了,如果今后有用户反馈说某一天流量消耗的比较多,我们就可以通过APM后台下发一条指令来回捞一下用户当天具体的流量消耗值,结合用户使用时长,就可以分析出用户的流量消耗是否存在异常。

3.3、前后台流量获取方案

场景:线上反馈App后台跑流量

很多用户对后台流量非常关心,大多数用户都是非常害怕你的应用在后台一直跑流量的,如果你只是使用上面讲到的这种方案,实际上我们并不知道消耗的这些流量前后台所占用的比例,所以只获取一个时间段的值不够全面,还需要知道这些流量到底是在前台消耗的还是在后台消耗的。

解决方案:

深入探索Android网络优化_第10张图片

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中添加缓存:

深入探索Android网络优化_第11张图片

就这两步就搞定了哦,然后来对比一下结果,没有缓存时关掉网络应用进去就是个空白页,有缓存的话即使关掉网络也是有数据能够展示的,给人一种好的用户体验:

深入探索Android网络优化_第12张图片深入探索Android网络优化_第13张图片

②、增量数据更新

  • 加上版本的概念,只传输有变化的数据
  • 配置信息

举个栗子:省市区等数据更新,这种类型的数据并不是经常变化的,如果每次都全量更新很明显造成了浪费,所以可以只更新有变化的那部分数据,这个场景需要和服务端实际配合,所以这里就不演示了,不过我相信大家也都明白是什么意思了。

③、数据压缩

  • 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,极大的减小了图片的体积,并且通过右侧两张图片放大后的效果可以看到图片的质量几乎看不出来有什么差别:

深入探索Android网络优化_第14张图片深入探索Android网络优化_第15张图片深入探索Android网络优化_第16张图片

所以图片压缩在使用过程中是相当重要的,一般情况下我们都要避免图片的原图上传。

④、优化发送频率和时机

  • 合并网络请求,减少请求次数:每个网络请求时都会有冗余信息,比如请求头,合并网络请求可以减少冗余信息的传递
  • 性能日志上报:批量+特定场景上报。对于成熟项目来说,会有很多性能日志埋点,这些数据最好不要在每次记录的时候都上传,而是记录的时候就只记录,在合适的时间点,比如用户处于WIFI环境下再去上传,这样对于用户的流量没有太大影响

⑤、图片相关

  • 图片使用策略优化:比如在列表展示时优先使用缩略图,直接展示原图只是扩大了内存的消耗并没有任何实际的意义
  • 使用WebP格式图片:在不改变图片尺寸的情况下可以有效的降低图片的物理体积,这个需要结合实际情况进行选择,因为可能实际使用的云服务并没有直接将jpg转换为webp的能力

缩略图:原图是32KB,生成的缩略图是6KB,大小有效减小了将近5倍多,并且针对于手机列表仍然是可以进行展示的,所以使用缩略图可以有效降低流量的消耗

深入探索Android网络优化_第17张图片

WebP:使用这种图片格式对于图片尺寸没有任何变化,但是图片大小也可以有效降低:

深入探索Android网络优化_第18张图片

五、网络请求质量优化

上一部分我们说了网络请求的流量优化,实际上对用户体验影响最大的是网络请求质量很差,这一点也是让人容易忽略的一个地方,我们开发测试阶段基本上都是在公司的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 lookup(String hostname) throws UnknownHostException {
        //优先使用阿里云dns解析服务返回的ip地址,如果为空再走系统的DNS解析服务
        String ip = dnsService.getIpByHostAsync(hostname);
        if(ip != null){ //如果不为空直接使用这个ip进行网络请求
            List inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));
            return inetAddresses;
        }
        return Dns.SYSTEM.lookup(hostname); //如果为空走系统的解析服务
    }
}

最后在OkHttp中设置自己的DNS解析服务:

深入探索Android网络优化_第19张图片

这样在网络请求的时候就可以绕过系统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 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中进行设置:

深入探索Android网络优化_第20张图片

通过上面的方法我们就可以拿到这次网络请求的每一步中包括dns解析的时间、request&response的时间、字节数等信息,这些数据都是做线上监控所必需的。

②、如何监听图片加载进度

关于图片加载现在大家也都是使用开源的解决方案,比较多的是Glide和Fresco了,我们需要做的是监听图片加载的整个过程,然后就可以计算出来每一步的耗时情况了,所以核心的是如何监听图片加载的全流程?这里具体的解决方案我就不再详细写了,下面把对应的链接提供给大家,直接点击查看详细的实现过程吧:

  • Glide:Android Glide4.0+图片加载进度监听 (更详细的分析见郭神的Glide系列文章吧:郭神Glide系列第七篇)
  • Fresco:Fresco加载图片

5.4、网络容灾机制

  • 备用服务器分流
  • 多次失败后一定时间内不进行请求,避免雪崩效应

5.5、其它优化

  • 资本层面:CDN加速、提高带宽、动静资源分离(更新后清理缓存)
  • 减少传输量,注意请求时机及频率
  • OkHttp的请求池:当前正在执行网络请求的任务数的最大值默认是64,单个Host可以同时运行5个网络请求,这样做可以防止某个域名的请求过多其它的域名请求没有机会执行

深入探索Android网络优化_第21张图片

六、网络体系化方案建设

线下测试

  • 方案:只抓单独App,将其余App的联网权限全部关闭
  • 侧重点:请求有误、多余,网络切换、弱网、无网测试

线上监控分为两个部分:服务端监控和客户端监控

服务端监控

  • 请求耗时(区分地域、时间段、版本、机型)
  • 失败率(业务失败与请求失败)
  • 排名靠前的失败接口、异常接口

客户端监控

  • 接口的每一步详细信息(DNS、连接、请求等)
  • 请求次数、网络包大小、失败原因
  • 图片监控

异常监控体系

  • 服务器防刷:超限拒绝访问
  • 客户端:大文件预警、异常兜底策略(连续多次请求失败暂停访问并加大重试时长)
  • 单点问题追查

OK,关于Android网络优化相关的介绍,就是上面这些了,那今天就先写到这里吧,各位小伙伴们,咱们下期再会!

祝:工作顺利!

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

你可能感兴趣的:(Android性能优化,Android网络优化,networkprofiler,抓包工具,stetho,流量优化)