Android客户端如何规避服务端数据格式错误导致的crash问题

crash

阅读本文大约需要3分钟

背景

场景如下:
应用新增了一个功能,升级了版本,客户端静默升级后,从桌面打开应用竟然出现了直接闪退、奔溃的现象!

测试:不能忍,无论如何,这是不允许存在的现象,怎么可以出现如此严重的bug!

服务端开发:这是由于新增的数据字段,没有被赋予正确格式的原因导致,测试只要在服务端推送数据时修改为正确的格式即可解决。

测试:服务端并没有约定说一定要填入那种格式的数据,我填入“非法数据”时,并没有被拒绝。我不管你们是怎么实现的,总之,不应该在引入新功能的时候发生如此严重的必现bug。

服务端开发:那在客户端那边加个try catch,规避这种crash的严重问题。

客户端开发:客户端不像服务端,不是所有的问题都是用try catch来解决就可以了,加try catch严重影响了效率问题。就不能在服务端那边控制一下,只传特定格式的数据吗?

分析

服务端发送给客户端的数据,由于不是指定格式的数据,导致客户端解析时出现问题,导致应用奔溃。

测试认为服务端传入的数据应该可以是任意的,而客户端必须要有容错机制,一定不能出现这种严重的crash问题。

而服务端为什么不控制一下,数据只能设置为指定格式数据,否则弹出非法数据警告提示呢?对服务端理解尚浅,不理解其中的原理,暂且就认为这是有一定道理的吧。

那么,我们就来探讨一下,如何从客户端出发,添加数据的容错机制吧。

前面开发建议,添加try catch,若接收到的数据为非法数据,则返回默认值。的确,这是解决问题的一种方案,至少,它能确保,不会因为数据格式问题导致crash的不能忍问题。

然而,try catch却要付出时间的代价。若代码中大量使用try catch来解决问题,一是代码不够简洁,二是若数据格式确实是非法的,则增加时间消耗。

为什么不考虑在做数据格式转换之前,先做一个数据格式检查,若为指定格式才对数据进行转换呢?这样一来,至少在代码简洁度上是更加有保障的。

为了对比以上两种方法的效率问题,我们用数据说话!

论证

目的:

对比try catch机制与先检查格式再转换的执行效率

准备:

A. 利用junit单元测试来测试代码块的执行时间,由于代码的执行都是闪速的,而junit测试也包含了一些初始化的准备时间,为了更加精确地统计代码的执行时间,采用循环100次取平均值及纳秒级别的时间差来做测试。

B. 从所在项目的情况来看,最主要问题存在于转化为long型时出错上,下一步的案例均基于long型数据的转化来设计,且基本上为项目中常用到的一些情况进行对比。

测试案例编写:

A. 直接得到的非法字符串转化为long型

非法字符串强制转换

B. 从SharedPrefrence中获取字段非long型强制转化为long型

获取字段后强制转换

C. 直接得到的纯数字String转化为long型

纯数字转换

结果对比:

将上步中的案例执行多次,进行耗时对比,为避免偶然性,进行了多次比较,以下随机截取了5次执行结果:从结果可以看出,虽然每次的执行耗时都略有不同,但相同的是:不管是在正确格式情况下还是非法数据强制转化,tryCatch的耗时都比通过正则表达式先判断数据格式再转换,平均多耗时1ms左右(执行100次的情况下),即执行1次约多耗时0.01ms。

结果1

结果2

结果3

结果4

结果5

结论

从第三部分的论证过程可以看出,先通过正则表达式判断后再做数据处理稍微比tryCatch方式高效率,虽然0.01ms是一个几乎可以忽略不计的时间,但编码是一种习惯、优秀也是一种习惯,不只是简单地用tryCatch来规避crash问题,而是找到问题的本质,并择优采取更合适的方式解决问题,这样不是更好吗?同时,尽可能避免tryCatch的使用,在一定程度上也能够提高代码的简洁度。

代码

文中涉及代码链接:GitHub