参考文档: https://www.cnblogs.com/xiaomaomao/p/16648099.html
源码查询网站: AOSPXRef
错误信息
crash 信息
Attempt to invoke interface method 'java.util.Iterator java.lang.Iterable.iterator()' on a null
object reference
堆栈信息
代码位置
可见是 mWaveList 调用 forEach 时, iterator 报的空指针,
让我们来看看 mWaveList 是怎么初始化的
val 也就是 final 类型, 类初始化的时候一定是被 new 出来的, 不可能为 null 啊?
由此想到了类构造方法, 成员变量, 静态变量, 静态方法等初始化时机, 再加上有继承关系的时的顺序!
错误分析
首先分析下错误代码位置, 是在重载 onVisibilityChanged 时抛出的, 难道这个时候 子类 还没有初始化完成?
跟着错误堆栈, 看了下流程, onVisibilityChanged 首次调用的实际 是在父类的构造器中, 调用顺序如下
View 构造器 -> setFlags(viewFlagValues, viewFlagMasks) -> dispatchVisibilityChanged -> onVisibilityChanged,
如果当前 view 在初始化时(比如在 xml 中设置为 gone)的 visibility 状态不为 visible, 就会分发这个显示状态变更了, 但! 此时还在执行父类的构造方法, 子类的实例还没有构造出来! 子类的成员变量也还没有初始化!!! 这就是 mWaveList 为 null 的原因!
此问题 仅在 5.1 以下手机上出现, 那就看下实现的区别吧
Android 5.0
Android 6.0 及以上版本实现
多判断了一个 mAttachInfo, mAttachInfo 则是在 dispatchAttachedToWindow 被赋值, 也就是此时 View 一定是初始化完成了的!
5.0 则没有此判断!
总结
其实主要需要知道类的加载顺序...直接给一个拷贝的结论:
优先级 1、父类静态成员变量 / 静态代码块
优先级 2、子类静态成员变量 / 静态代码块
优先级 3、父类非静态成员变量 / 父类构造代码块 (创建子类对象必须先调用父类的构造方法,完成父类属性的初始化)
优先级 4、父类构造方法
优先级 5、子类非静态成员变量 / 父类构造代码块
优先级 6、子类构造方法