1、微信超级Bug

大家好,给大家介绍一下,这是Bug:

应该有很多Android的用户熟悉上面这图。

(本文同步发布于:http://www.52im.net/thread-1099-1-1.html)

2、事件背景

国庆前几天,微信Android大量用户反馈接收或发送类似“15。。。。。。。。。。。。。。。”信息会导致微信聊天界面卡死,程序崩溃。这对微信来说是很严重的事情啊,一时半会反馈也铺天盖地的过来,我们得知这个问题后,第一时间对这个问题进行了紧急修复并在两天内覆盖了全网大部分用户,最终这个问题得到了解决。追根溯源,毫无疑问这锅开发小弟来背,这次不能冤枉了产品MM哈哈。

与此同时,很多热心的网友也开始分析原因,25号当日就有行内大神通过ANR日志和反编译debug,一步步推敲出此次ANR的根源,给出了卡死的原因。请受小弟一拜,实在佩服佩服!

详情可参考链接:http://androidwing.net/index.php/243

下图是网友分析结果图:

根据该网友的推敲,此次卡死的真正原因在于:“这个wwk是始终等于0的,也就是不满足while内部的dVar2的置空条件,也就造成了while死循环”。这里具体怎么做到动态反编译的?

这个知乎的回答很详细:https://www.zhihu.com/question/65828771

3、真正原因揭晓

真正的原因确实如网友分析的,主要是卡在了这个while循环里面,这个循环的主要作用是将当前文字内容按具体的规则进行断句排版,见下图。

因为dVar2且dVar2.getText一直不为空,一直满足这个条件,所以造成死循环。

而dVar2这个值为null的条件取决于下面这个函数:

“i4”变量实际是断句算法返回截断的实际位置,dvar2.getLength()实际是当前行的文字长度,这里因为断句算法的bug,造成了”i4”这个变量一直返回0,而当前行文字长度dvar2.getLength()是>0的,所以这个dVar2永远不会被赋值为空。

继续追根问底:是什么原因造成断句算法一直返回0呢,实际上断句算法是调用了以下这个函数:

该函数返回了一个对象a其包含两个参数,一个是断句的位置(a.wwk),及断句后的文字长度(a.width),主要是因为在判断换行的时候,因为考虑到标点符号不应该位于行首这条规则,需要将当前行最后一个非标点符号截断到下一行,而截断受另外一条规则限制,截断不可以为英文或者数字,这导致“15。。。。。。。。。。。。。。。”最后返回截断的位置为0,并将结果返回,所以才产生了死循环,造成这个bug。

4、那么问题来了

很多网友也开始讨论,为什么要自己排版,放着好端端的系统TextView不用?到底好在哪里?效果是怎么样的?

不着急,诸多问题的来龙去脉得容小弟一一道来。

5、为什么有这个需求?

实际上,世界上大部分需求都源于用户。这需求还得得益于之前有几个用户会反馈说“微信Android的聊天气泡好像没有iOS的美观,比较死板”。这个问题也引起了我们的关注。

那事实是否如此呢?我们对iOS和Android进行了对比,如下图:

从效果图看,iOS确实比Android好看了些,至少最右边并不会有多余的padding这么明显,简单来说多余的padding产生的原因是气泡宽度受屏幕大小的限制,所以这里TextView即是气泡有了最大的宽度限制,当剩下的空间不足以容下一个字符时,系统排版会选择自动换行,导致了这个问题的产生。

6、又一个问题

那么,iOS的排版是否就是完美的呢,其实仔细观察并非这样,从上图可以看出,除了Android,iOS也会有这种问题,那就是气泡中的文字左右参差不齐。

一开始我们怀疑,会不会是微信应用本身使用该组件不当的原因造成,而非系统组件的问题。于是乎,在手机上,我们随便找了一些热门app,仔细对比,同样的问题依然存在。

知乎:

掘金:

支付宝:

等等。。。

而且除了移动端,pc端同样也有诸类问题。结合上面这些对比,确实市面上大部分应用都存在这个问题。通过这次反馈,我们也开始在思考能不能在移动客户端的文字排版上做得更人性化一些,体验上更好?。就这个问题,我们找了设计的同学一起探讨,认为确实有这个必要。于是就开始有了下一步。

7、排版要怎么排?

对于文字排版,这容易让人想起,“我的(word)哥”,微软对于这款应用,有没有一些文字左右对齐的手段或者方案可以参考呢?

下图为word的左对齐效果,也就是Android的TextView默认对其方式:

下图为word的居中‘硬’对齐效果:

下图为word的居中‘软’对齐效果:

从这种效果上看,“软对齐方式”更美观,体验最好。于是我们能想到的就是动态调整字间距的方式来实现这种效果(word也是这么实现的)。

那既然要动态调整字体间距,是不是可以一味的这么做就可以?答案当然不是,如果这么做就像‘硬对齐方式’一样,显得过于生硬了。

我们就这个问题跟设计组的同事进行讨论,通过他们的调研及尝试,得出了一个合理的方案,那就是最多允许有一个英文字符宽度的调整范围,将调整的宽度平均分配到当前行每个字符中去,对用户来说影响是最小的,同时也保持了一定的美观。

8、实践自定义排版

对于Android来说,实现这条规则并不难,要么是改造系统TextView,要么自己写个自定义view实现文字排版及渲染,最后我们采用了后者这个方案。

原因在于:

系统TextView真正排版及绘制的逻辑不在其本身,而是交给三个继承了Layout的子类负责,分别为StaticLayout、DynamicLayout、BoringLayout,我们更常用的是StaticLayout,它只负责静态的文字处理,关于各自Layout的区别,这里了就不展开讲了。系统TextView并没有暴露接口去代理它们。当然没有接口不意味着做不到,我们完全可以通过反射等手段代理它,但其实这么做的话,代价是比较大的。

原因有三:

1)其一:从Android 2.3到Android 8.0,TextView的代码虽说变化不会很大,但从Layout来看,实现的逻辑或者接口也好都有所变更,如果通过这个方式,代理的兼容性会是一个问题;

2)其二:TextView堪称Android最复杂的一个组件之一,几个Layout逻辑代码的复杂程度很高,自己实现所有的Layout接口,本身就是一件复杂且工作量很大的工作;

3)其三:实际上自己实现一个Layout,基本上就实现了一个显示组件,排版和渲染都是要处理的,所以这样实现的意义不大,甚至反而不灵活。

回归正题,我们对系统TextView的规则进行对比,最后我们确定了以下几条规则:

1、最多允许有一个字母字符宽度的来调整字间距;

2、对于标点符号尽量规避不出现在行首;

3、对于英文单词或数字不截断排版。

于是我们开始进行简单的demo实现。效果如下图:

对比优化前的效果,确实这么做效果是明显的。但仔细观察,还是会发现,对于一些特殊的中文全角符号(如,《》()【】等)因为有多余的padding存在,放在行首和行末也会导致参差不齐的效果。

于是我们多增加了一条规则:

对一些常见的有多余padding的全角符号位于行首或行末时,默认减去多余的padding来达到更好的对齐效果。

最后的优化效果,如图:

最后一张是应用了4条规则的效果图,整体文字的对齐效果比系统默认的排版改善了不少。

9、问题又来了

那既然效果是不错的,是否存在其他问题?确实如此。

9.1 小语种处理问题

因为微信对小语种是支持的,对于一些特殊的小语种,如泰语,阿拉伯语等,泰语的排版方式并非简单的横排,字符与字符之间是有上下关系的,而对于阿拉伯语,是从右往左排列的。如果只是按上面所讲的几个规则,那么排版后的效果肯定是不合理的。

考虑到小语种存在多样性,排版规则不统一,而且使用小语种用户比例小,但也不能让其排版错误不管,所以对于这种情况,我们通过一个简单的正则表达式去匹配是否属于能处理的字符串范围内,这就是为什么有网友分析”15。。。。。。。。”这个事件时,一开始会怀疑是正则匹配耗时造成的。

下图为该网友的分析:

而实际上,这个简单的正则表达式,如该网友测试的一样,处理起来很快,基本都在1ms内,对性能的影响可忽略。通过正则去判断后,如果是可处理的字符串则应用上面的规则进行排版,如果是特殊的字符串,则用系统的TextView代理显示。

9.2 适配率问题

既然小语种的问题可以解决,但这里又产生一个问题,现网上的用户, 使用特殊字符的频率多高?这问题直接关系到我们这个排版组件的适配率,也就是对用户体验改善多少?在我们看来,一般人并不会发些奇奇怪怪的符号在微信里面,所以能应用上这个排版规则的应该占大多数。当然这里只是猜想,如果这样确定可行性也太草率了。

于是我们针对这个问题,进行了一轮灰度,灰度的结果如下:

通过这次灰度,现网用户能应用上该组件适配的情况达到了预期的结果。

9.3 性能问题

如果该组件的性能跟系统相差太多,甚至严重影响帧率,造成用户卡顿,这当然也是不可取的。我们针对这个问题,进行了本地的自动化帧率测试及与系统TextView进行函数间的对比。

下图是实验数据:

得出结论:

从微观上:通过函数进行对比,CellTextView对比系统TextView性能稍差2倍,主要差距在于绘制文字时需要单字调整间距;

从宏观上:CellTextView对实际帧率的影响较小,用户无明显感知性能变差。

通过以上的尝试及灰度结果来看,做这个事情其实是很有意义的,那么最后也敲定下了这个优化方案。

10、事件结尾

整个需求的来龙去脉就是这样子的,其实梳理这个过程的来龙去脉来,一来可以让自己不断反思该过程存在的一些问题,二来呢,因为本次bug确实对大家造成了不好的影响(真的是深感歉意啊!),可以让大家清楚这个事情是怎么发生的,至少大家不会卡得不明不白的。

写代码万万要小心谨慎,考虑周全啊。这次痛定思痛,吃一堑,长一智吧。愿天下的程序统统没有bug。对,统统没有!

最后贴上一张优化后的效果图:

文章写得不好的地方,望见谅,大神莫喷莫喷。小弟我要背锅去面壁了。

(原文链接:点此进入)

附录:更多微信、QQ技术文章汇总

[1] 有关QQ、微信的技术文章:

《微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉》

《QQ 18年:解密8亿月活的QQ后台服务接口隔离技术》

《月活8.89亿的超级IM微信是如何进行Android端兼容测试的》

《以手机QQ为例探讨移动端IM中的“轻应用”》

《一篇文章get微信开源移动端数据库组件WCDB的一切!》

《微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化》

《微信后台基于时间序的海量数据冷热分级架构设计实践》

《微信团队原创分享:Android版微信的臃肿之困与模块化实践之路》

《微信后台团队:微信后台异步消息队列的优化升级实践分享》

《微信团队原创分享:微信客户端SQLite数据库损坏修复实践》

《腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率》

《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》

《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)》

《微信Mars:微信内部正在使用的网络层封装库,即将开源》

《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》

《开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]》

《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》

《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》

《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》

《Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]》

《微信团队原创分享:Android版微信从300KB到30MB的技术演进》

《微信技术总监谈架构:微信之道——大道至简(演讲全文)》

《微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]》

《如何解读《微信技术总监谈架构:微信之道——大道至简》》

《微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]》

《微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案》

《微信朋友圈海量技术之道PPT [附件下载]》

《微信对网络影响的技术试验及分析(论文全文)》

《一份微信后台技术架构的总结性笔记》

《架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]》

《快速裂变:见证微信强大后台架构从0到1的演进历程(一)》

《快速裂变:见证微信强大后台架构从0到1的演进历程(二)》

《微信团队原创分享:Android内存泄漏监控和优化技巧总结》

《全面总结iOS版微信升级iOS9遇到的各种“坑”》

《微信团队原创资源混淆工具:让你的APK立减1M》

《微信团队原创Android资源混淆工具:AndResGuard [有源码]》

《Android版微信安装包“减肥”实战记录》

《iOS版微信安装包“减肥”实战记录》

《移动端IM实践:iOS版微信界面卡顿监测方案》

《微信“红包照片”背后的技术难题》

《移动端IM实践:iOS版微信小视频功能技术方案实录》

《移动端IM实践:Android版微信如何大幅提升交互性能(一)》

《移动端IM实践:Android版微信如何大幅提升交互性能(二)》

《移动端IM实践:实现Android版微信的智能心跳机制》

《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》

《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》

《移动端IM实践:iOS版微信的多设备字体适配方案探讨》

《信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑》

《腾讯信鸽技术分享:百亿级实时消息推送的实战经验》

>>更多同类文章 ……

[2] 有关QQ、微信的技术故事:

《技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码》

《技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史》

《技术往事:“QQ群”和“微信红包”是怎么来的?》

《开发往事:深度讲述2010到2015,微信一路风雨的背后》

《开发往事:微信千年不变的那张闪屏图片的由来》

《开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)》

《一个微信实习生自述:我眼中的微信开发团队》

《首次揭秘:QQ实时视频聊天背后的神秘组织》

>>更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-1099-1-1.html)

微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉相关推荐

  1. 微信公众号助手android,微信团队发布微信公众号订阅号助手App

    原标题:微信团队发布微信公众号订阅号助手App " 微信团队发布「订阅号助手」App,支持公众号运营者在手机上发表内容.查看和回复消息.管理已关注用户和帐号.暂时只支持iOS平台,Andro ...

  2. 微信订阅号与微信后台服务器的接入不成功,微信团队:微信公众平台重在连接用户和服务...

    腾讯科技讯 7月3日消息,今天,在腾讯合作伙伴大会微信分论坛现场,微信产品部助理总经理曾鸣表示,微信公众平台的本质是服务,提升用户体验,才能创建良好的生态系统. 微信产品部助理总经理曾鸣(腾讯科技配图 ...

  3. 深度linux登录后界面卡死,Deepin Linux 15(.1)启动即卡死的问题

    以wubi方式安装的Deepin Linux最新的15版系统,几分钟就安装完成了.可是启动时,登陆进去,一会儿就死机,只有鼠标能动,键盘都动不了.我觉得是显卡驱动问题,所以就更新了最新的驱动,启动后系 ...

  4. 微信团队分享:微信移动端的全文检索多音字问题解决方案

    本文来自微信开发团队WeMobileDev公众号的技术分享. 1.前言 微信的移动客户端全文搜索中的多音字问题一直是搜索体验的痛点之一.微信客户端全文搜索在上线以后,也经常收到用户关于多音字问题的反馈 ...

  5. 微信团队分享:iOS版微信的高性能通用key-value组件技术实践

    本文来自微信开发团队guoling的技术分享. 1.前言 本文要分享的是iOS版微信内部正在推广和使用的一个高性能通用key-value 组件的技术实践过程,该组件在微信内部被命名为MMKV(以下简称 ...

  6. 微信团队分享:微信每日亿次实时音视频聊天背后的技术解密

    本文内容整理自腾讯专家研究员 & 微信视频技术负责人谷沉沉在 2017 ArchSummit 全球架构师峰会上的技术分享. 1.前言 2012 年 7 月,微信 4.2 版本首次加入了实时音视 ...

  7. 微信团队原创分享:iOS版微信的内存监控系统技术实践

    为什么80%的码农都做不了架构师?>>>    本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在 ...

  8. 微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

    本文原文由微信客户端高级工程师方秋枋原创发表于WeMobileDev公众号,收录时有修订和加工,感谢作者的无私分享. 1.引言 作为一个重要业务,微信支付在客户端上面临着各种问题. 其中最核心问题就是 ...

  9. 微信团队分享:视频图像的超分辨率技术原理和应用场景

    为什么80%的码农都做不了架构师?>>>    本文来自微信多媒体团队高欣玮的技术分享. 1.前言 图像和视频通常包含着大量的视觉信息,且视觉信息本身具有直观高效的描述能力,所以随着 ...

最新文章

  1. Java过滤器与SpringMVC拦截器之间的关系与区别
  2. 策略模式和php实现
  3. 从工具到社区,美图秀秀大规模性能优化实践
  4. 如何对系统中设置的修改记录增加log日志
  5. 经典C语言程序100例之五零
  6. spring注解方式 idea报could not autowire
  7. 2020年“1024”,程序员日
  8. JavaScript | 声明数组并使用数组索引分配元素的代码
  9. 读书笔记:《Aspx开发200问》——如果实现动态加载用户空间
  10. 经典面试题(50):以下代码将输出的结果是什么?
  11. swift之Mac中NSView视图里的截图【ScrollView中的内容截图】
  12. scratch数学编程100例_《scratch编程+数学》课程:编程实现数字黑洞冰雹猜想
  13. 结对项目:电梯调度算法的实现和测试
  14. spring-boot 加载本地静态资源文件路径配置
  15. 伊顿UPS电源说明书-伊顿UPS电源使用手册
  16. word2016如何在将指定页设置为首页
  17. 击破“坪效”天花板,从“3050法则”看餐饮数字化迁徙
  18. 写一个旅行青蛙攻略APP
  19. Error:A JNI error has occurred, please check your installation and try again的解决方法
  20. 硬纪元AI峰会前瞻:火爆的无人驾驶还将有哪些深度创新?

热门文章

  1. 1.5.6.六种常见的三角关系
  2. 哥德巴赫猜想两种题目解法
  3. mysql自学教学_MySQL自学篇(三)_MySQL
  4. 用plink ssh打开wireshark 连接openwrt tcpdump获取抓包数据
  5. git clone报错:repository ‘xxxxxxxxx’does not exist
  6. cl.ez6.xyz index.php,[BJDCTF2020]EzPHP-POP链
  7. 智伴机器人三级分销模式_三级分销系统的模式有哪些
  8. Python学习笔记(一)——Anaconda安装与配置(windows)
  9. 笔记本修改无线网卡MAC地址
  10. 谷歌浏览器自带的翻译功能无法使用的解决办法