Android兼容性问题 -- RelativeLayout.mesure()出现NullPointerException异常

View的高度获取问题

在Android中一个View被创建后是不能够立刻知道其宽度和高度的。
如下代码试图在footerView创建后,通过其getWidth()和getHeight()方法得到其宽度和高度,实际得到的width和height都等于0。

View footerView = View.inflate(this, R.layout.list_footer, null);
int width = footerView.getWidth();
int height = footerView.getHeight();

这是因为,在Android中一个View在创建完成后还需要经过测量(measure),布局(layout)和绘制(draw)三个步骤才会显示出来。其宽度和高度也只有在测量完成后才能够获取到,如果在测量之前就尝试获取其宽度和高度,只能得到0。
因此,如果要获取一个View的宽度和高度,通常可以等待其测量完成后再尝试获取。在Android中提供了一些监听事件,可以在布局完成,或绘制之前通知监听者。由于这时已经测量完成,就可以直接获取View的宽高了。
如下代码均可以得到footerView的宽度和高度。

footerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        footerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        int wight = footerView.getWidth();
        int height =footerView.getHeight();
    }
});
footerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        footerView.getViewTreeObserver().removeOnPreDrawListener(this);
        int wight = footerView.getWidth();
        int height =footerView.getHeight();
        return false;
    }
});

View高度的手动测量

虽然可以通过注册监听的方式来获取View的宽度和高度,但这时通常都已经完成了布局,如果我们需要在获取到View的宽度和高度后再对View的布局做额外的调整,要么是没有效果,要么是需要重新布局,影响效率,甚至可能会出现一些界面闪烁。因此,对这类需要根据某个View的宽度或高度做重新布局的时候,就需要在View创建完成后能够立刻得到其宽度和高度。要想实现这点,可以通过手动执行View的measure方法。示例代码如下。

int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
footerView.measure(width, height);
int width = footerView.getMeasuredWidth();
int height =footerView.getMeasuredHeight();

RelativeLayout 执行measure方法异常

上述代码对根Layout为FrameLayout,LinearLayout的View都能够正常工作,但是对根Layout为RelativeLayout的View,可能会出现如下的NullPointerException异常。
Android兼容性问题 -- RelativeLayout.mesure()出现NullPointerException异常_第1张图片

问题原因

产生此异常的原因是RelativeLayout在Android4.4以下版本中的一个bug。此bug已在Android4.4版本中修正。以下是Android4.0和Android4.4版本RelativeLayout的部分源码对比。

可以看到在Android4.0版本中没有判断mLayoutParams是否为null,如果mLayoutParams为null就会抛出NullPointerException异常。而在Android4.4版本中增加了对mLayoutParams是否为null的判断。

解决方法

由于此bug只在RelativeLayout中存在,只需要在RelativeLayout布局外面再嵌套一层FrameLayout或者LinearLayout即可。

你可能感兴趣的:(Android兼容性问题 -- RelativeLayout.mesure()出现NullPointerException异常)