RelativeLayout的坑

背景:
因为某个功能,修改了listview的header的根布局,由原来的FrameLayout改为了RelativeLayout,目的是这样能更方便的去处理header里的各个元素之间位置。

Bug出现场景:
在Android4.2及以下的手机上加载列表的时候必崩,错误日志如下:
这里写图片描述
刚开始没有关注BtsViewUtil的155行,因为这个是一个用了很久的工具类,主要就是对view进行measure,应该没啥问题;而addHeaderView的第259行也是PinListView的自带方法,用了很久了,应该也没问题,然所以最后就把注意力放在了我自己写的代码BtsRouteOrderListFragment.addOriginHeaders里,主要代码就一句:

mPinListView.addHeaderView(mHeaderView);
看到是空指针异常,感觉应该比较容易解决,但是通过断点排查发现,这个地方地方不会存在为null的控件,可是日志确实显示是这个地方,而且是必现,这个null指针异常就显得很诡异了。
找不到原因,只能把修改的代码一点点回退,知道修改完header的布局文件,把RelativeLayout布局改回成FrameLayout后,代码成功运行了。。。
虽然一脸懵逼,不过因为是在低版本才会出现这个问题,心想可能是RelativeLayout的兼容性问题,查阅了一下官方文档,看到里面有个注释:
这里写图片描述
大致意思就是 在api17以前的版本,RelativeLayout有一个bug,就是在一个可以scrolling的容器中进行measure的话,如果自定义view没有使用UNSPECIFIED的话,就会默认使用AT_MOST来代替;确实是个坑,但是貌似和咱们这个空指针没太大关系。。。
无奈只能看源码,既然错误日志是在onMeasure里发生的,那就看看RelativeLayout的onMeasure方法。
api 18的代码:
这里写图片描述
因为刚开始进行初始化的时候,headerview只是被渲染出来,还没有attach到View层次树,所以这个mLayoutParam是null,这里就会报错;
而API 19的代码:
这里写图片描述
已经做了防护,所以新版本不会崩溃。
这也说明了为什么最开始的错误日志会显示在BtsViewUtil.java:155。

那FrameLayout应该有同样的问题啊,为什么不会崩溃?
看了下FrameLayout的代码,它里面压根没有用到mLayoutParam,所以不会崩溃。。

结论:1、在api 17之前,如果在scrollview或listview中使用ReletiveLayout,尽量不要手动调用measure。
2、在measure之前显式设置LayoutParams(代表着对父View的Layout请求,必须是父View的内部LayoutParams类型)

发布了61 篇原创文章 · 获赞 9 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/fly_yuge/article/details/75448893