【吐血🤮】一次生产环境NPE崩溃的排查记录(中)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 直接说引起NPE的根本原因: rx订阅没有取消,回调时Fragment已经被回收,引用view调更新方法,自然NPE。

你可能有疑问,为啥要在onDestroyView()里清空Map,而不是onDestory()里?


答:考虑到Fragment复用的场景,具体如下:


replace() Fragment 后会执行 onDestoryView(),而不是执行onDestory()完全销毁,目的是在销毁视图的同时,保留View状态和Fragment成员状态,下次加载时可以直接走onCreateView(),更快加载以达到复用的目的。


关于View状态的保存机制,笔者也不是特别了解,大概瞄下TextView的源码(onSaveInstanceStateonRestoreInstanceState),看到了实现Parcelable重写了一些方法,猜测是 序列化。而序列化和反序列化前后,对象实例是不相等的,此时Map里还保留这之前的键值对(id → 实例),此时根据id拿到的View实例肯定是不对的,所以这里做了清空操作。


所以这里也没毛病,所以不是KAE的锅,虽然这里不涉及,但也把Adapter情况如何findViewById也过一下~


KAE不支持直接在adapter里直接用,需要在build.gradle添加下述实验性配置:


// 主要是为了启用LayoutContainer   
androidExtensions {
    experimental = true
}


而调用方式其实分两种,第一种是这样:


网络异常,图片无法展示
|


看下字节码转Java:


网络异常,图片无法展示
|


直接findViewById的,看看另一种,让ViewHolder实现LayoutContainer的方式:


网络异常,图片无法展示
|


看字节码转Java:


网络异常,图片无法展示
|


原理同样是创建一个hashMap来保存引用,通过ViewHolder传进的View进行绑定,真要在adapter里用KAE,建议使用第二种。


《Kotlin Android Extensions遭废弃,官方推荐使用ViewBinding》 一问中说到KAE的问题:


网络异常,图片无法展示
|


除此之外空间换时间,用一个额外的HashMap来存储View实例,更重要的是这部分内容对大部分使用者而言是黑盒,有时会踩上一些莫名其妙的"坑"。


官方提了一嘴使用ViewBinding替代KAE,其实就是启用ViewBinding功能后,AS自动为每个布局文件生成一个对应的Binding类,在里面完成View绑定(包含判空),文件输出目录:/build/generated/data_binding_base_class_source_out


具体玩法可以参见:《kotlin-android-extensions插件也被废弃了?扶我起来》


0x3、灵光乍现的瞬间


排查完不是KAE的锅,那到底是什么原因导致的控件为空呢?排查进展一下子陷入了僵局,只能从用户行为入手了,友盟上不知道为何看到不到用户的行为日志。


好在有自家全埋点,打开 Kibana,过滤错误类型日志,找到错误日志,获取deviceid,然后查询用户行为。


网络异常,图片无法展示
|


通过分析多个用户报错的情况,我发现了一个规律:


都是一次首页的Loading,然后崩溃,而距离用户上次打开APP的时间一般都会很久。


脑子里突然蹦出一个想法,该不会是因为APP被回收,重新打开Activity重建的问题把,因为APP中有一个跟很多APP一样的鸡贼操作,虽然提示了 "再按一次退出程序",但其实是调用moveTaskToBack()退到后台而已。


网络异常,图片无法展示
|


模拟APP被回收就简单了,AS跑下程序,来到出问题的页面,APP退到后台,直接在Logcat把程序干掉,接着重新打开程序,静待片刻,果然,崩溃了,看下日志信息:


网络异常,图片无法展示
|


好家伙,果然复现了,因为Activity重建导致的刷新控件为空,噼里啪啦跟组长解释一波崩溃的原因,然后应急处理方式就是调用前先判空,保证不崩溃先。


本来快到下班的点了(6点),正常情况应该是吃点东西摸鱼等下班了,不过没搞清楚引发这个问题的具体原因,回家也是念念不忘,索性加班排查下吧。


0x4、加班加点排查


涉及Activity重建,那估计也跟Fragment生命周期,Fragment多层嵌套之类的脱不了干系,在BaseActivity和BaseFragment中把生命周期相关的回调都加上日志。


网络异常,图片无法展示
|


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
JavaScript IDE Java
bugly崩溃排查3:观察是谁调用了崩溃函数
bugly崩溃排查3:观察是谁调用了崩溃函数
27 0
|
11月前
|
Java Linux
|
12月前
|
运维 监控 前端开发
记一次线上 bug 的排查分析过程及总结
记一次线上 bug 的排查分析过程及总结
记一次线上 bug 的排查分析过程及总结
|
消息中间件 运维 监控
线上踩坑记:项目中一次OOM的分析定位排查过程!
线上踩坑记:项目中一次OOM的分析定位排查过程!
|
安全 Java
Java开发过程中 异常及日常如何规避
Java开发过程中 异常及日常如何规避
|
测试技术
软件测试面试题:自动化遇到用例fail掉如何排查故障?
软件测试面试题:自动化遇到用例fail掉如何排查故障?
112 0
|
JSON Java 程序员
写了这么久的业务连异常都不知道怎么处理吗
前言 文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820… 种一棵树最好的时间是十年前,其次是现在
197 0
【吐血🤮】一次生产环境NPE崩溃的排查记录(下)
直接说引起NPE的根本原因: rx订阅没有取消,回调时Fragment已经被回收,引用view调更新方法,自然NPE。
128 0
|
测试技术 Kotlin
【吐血🤮】一次生产环境NPE崩溃的排查记录(上)
直接说引起NPE的根本原因: rx订阅没有取消,回调时Fragment已经被回收,引用view调更新方法,自然NPE。
241 0
|
Web App开发 运维 安全
印象最深的一个bug——排查修复问题事件BEX引发的谷歌浏览器闪退崩溃异常
本文记录了目前修复的千千万万个项目的BUG中印象最深的一次BUG,由于问题事件BEX引发的谷歌浏览器闪退崩溃的异常问题.这个BUG因为其不可复现性导致特别难以发现和解决,正是由于这一次的BUG解决过程,让我了解到了一位攻城狮在项目开发维护过程中实际经验的重要性,多思考,多实践,多多积累经验,才是一位攻城狮的成长之路.
30619 2
印象最深的一个bug——排查修复问题事件BEX引发的谷歌浏览器闪退崩溃异常