Android RelativeLayout.mesure()时出现NullPointerException异常

在部分Android版本中,使用RelativeLayout进行自定义视图并尝试测量尺寸时可能会遇到空指针异常。本文详细介绍了该问题的原因及其解决方案。

        先说说怎么发现的这个问题,项目中使用的是百度地图,在搞百度地图的时候,需要在地图上添加Marker(标注覆盖物),自定义一个布局文件,根Layout为RelativeLayout,然后将自定义的布局文件转换成Bitmap,然后转换成BitmapDescriptor(BitmapDescriptor是百度地图的,这里不是重点),之后添加标注,显示在地图上。做完之后运行测试,没有问题,换一个手机测试,也没有问题,再换一个手机,同样没问题。好了,提交代码。原本以为这点小事就做完了,结果同事更新下来代码之后运行,程序崩溃了,竟然崩溃了......崩溃了.......,我立马拿他手机测试了一下,确实是崩溃了,这尼玛也是醉了。看了一下错误日志,竟然是空指针异常疑问

异常信息:


定位到代码:

    private BitmapDescriptor changeToBitmap(View view) {

        view.setDrawingCacheEnabled(true);

        view.measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        view.layout(0, 0,
                view.getMeasuredWidth(),
                view.getMeasuredHeight());
        view.buildDrawingCache();
        Bitmap cacheBitmap = view.getDrawingCache();
        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
        BitmapDescriptor icon = BitmapDescriptorFactory.fromBitmap(bitmap);
        return icon;
    }
        发现是view.measure这一行报错,在我测试的其他3部手机上都没问题,结果在这个手机上出问题了,当时第一想法就是android版本的问题,看一下版本,我测试过的3部手机版本分别是21、22、23(即5.0.1、5.1、6.0)没有问题,有问题的那部手机API为17(即android4.2版本),怎么会这样呢,难道view.measure方法在不同的版本源码不同???在线看了一下android源码,尼玛,还真有问题。

首先看官方这么一段话:


大概翻译一下就是:

在平台版本17(包含17)或更低,RelativeLayout会受测量错误的影响导致子视图测量不正确,在RelativeLayout的控件使用在含有scrolling的时候,该含有scrolling的控件中计算空间大小,没有使用MeasureSpec mode UNSPECIFIED的布局方式在RelativeLayout。自定义的控件则会尽可能的使用AT_MOST 来替换对齐方式。

这种行为已经保存应用程序设置Android的targetSdkVersion =“17”或以上的清单的使用SDK标签的兼容性。针对SDK 18版或更新版的应用程序将获得正确的行为。

说人话就是RelativeLayout在API17及以下版本使用measure方法是有BUG的,会出现空指针异常,18及以上是没有问题的。

再看一下RelativeLayout的onMeasure源码(既然官方说18(即android4.3)修复了,那就对比之前的看一下有什么不同吧):


        左边是18(android4.3),右边是19(android4.4),可以看到,在4.4版本中增加了非空判断,之前版本没有这个。(说到这我又想吐槽了,刚刚官方明明说18就已经解决这个BUG了,为什么在19上才看到这个非空判断,也是无语。。。)

       好了,啰啰嗦嗦那么多,总之就是:

RelativeLayout.measure方法在android4.4版本之后没有空指针异常这个BUG,但之前版本会抛出空指针异常。

解决方法:

在RelativeLayout布局外面再嵌套一层FrameLayout或者LinearLayout即可。


相信会有好多像我一样不知道这个坑的猿猿们,希望能帮到你们。

这段 Kotlin 代码是在创建一个 `RelativeLayout.LayoutParams`,用于在代码中动态设置某个视图(View)在 `RelativeLayout` 中的布局参数。它的作用是让该子视图**和父容器 `RelativeLayout` 一样大**,并且**与父容器的上下左右四边对齐**,也就是**填充整个父容器**。 --- ### ✅ 对应的 XML 布局参数是: ```xml <YourView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" /> ``` 其中 `YourView` 可以是任意子视图(如 `TextView`, `ImageView`, `View` 等)。 --- ### 🧠 逐行解释 Kotlin 代码: ```kotlin is RelativeLayout -> RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ).apply { addRule(RelativeLayout.ALIGN_PARENT_START) addRule(RelativeLayout.ALIGN_PARENT_TOP) addRule(RelativeLayout.ALIGN_PARENT_END) addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) } ``` | 代码 | 含义 | |------|------| | `ViewGroup.LayoutParams.MATCH_PARENT` | 宽高都设置为填满父容器 | | `addRule(RelativeLayout.ALIGN_PARENT_START)` | 与父容器左对齐(RTL 自适应) | | `addRule(RelativeLayout.ALIGN_PARENT_TOP)` | 与父容器上对齐 | | `addRule(RelativeLayout.ALIGN_PARENT_END)` | 与父容器右对齐(RTL 自适应) | | `addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)` | 与父容器下对齐 | > 这些规则共同作用的结果就是:子视图会和父容器一样大,即“match_parent”效果。 --- ### ✅ 使用场景举例: 当你想在代码中动态添加一个 View 到 `RelativeLayout` 中,并让它填满整个布局,就可以使用这段代码设置 `LayoutParams`。 ```kotlin val view = View(context) view.layoutParams = RelativeLayout.LayoutParams(...).apply { ... } relativeLayout.addView(view) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值