1. 典型的再现环境

    模型: Sony Ericsson

    Android version: 2.3.4

    StackTrace:

    E/AndroidRuntime( 3579): FATAL EXCEPTION: main
    E/AndroidRuntime( 3579): java.lang.NullPointerException
    E/AndroidRuntime( 3579): at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:431)
    E/AndroidRuntime( 3579): at android.view.View.measure(View.java:8462)
    E/AndroidRuntime( 3579): at com.example.measureverify.MainActivity$MenuListAdapter.getView(MainActivity.java:85)
    E/AndroidRuntime( 3579): at android.widget.AbsListView.obtainView(AbsListView.java:1519)
    E/AndroidRuntime( 3579): at android.widget.ListView.measureHeightOfChildren(ListView.java:1220)
    E/AndroidRuntime( 3579): at android.widget.ListView.onMeasure(ListView.java:1131)
    E/AndroidRuntime( 3579): at android.view.View.measure(View.java:8462)
    E/AndroidRuntime( 3579): at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:581)
    E/AndroidRuntime( 3579): at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:365)
    E/AndroidRuntime( 3579): at android.view.View.measure(View.java:8462)
    E/AndroidRuntime( 3579): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3231)
    E/AndroidRuntime( 3579): at android.widget.FrameLayout.onMeasure(FrameLayout.java:254)
    E/AndroidRuntime( 3579): at android.view.View.measure(View.java:8462)
    E/AndroidRuntime( 3579): at android.widget.LinearLayout.measureVertical(LinearLayout.java:535)
    E/AndroidRuntime( 3579): at android.widget.LinearLayout.onMeasure(LinearLayout.java:313)
    E/AndroidRuntime( 3579): at android.view.View.measure(View.java:8462)
    E/AndroidRuntime( 3579): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3231)
    E/AndroidRuntime( 3579): at android.widget.FrameLayout.onMeasure(FrameLayout.java:254)
    E/AndroidRuntime( 3579): at android.view.View.measure(View.java:8462)
    E/AndroidRuntime( 3579): at android.view.ViewRoot.performTraversals(ViewRoot.java:861)
    E/AndroidRuntime( 3579): at android.view.ViewRoot.handleMessage(ViewRoot.java:1882)
    E/AndroidRuntime( 3579): at android.os.Handler.dispatchMessage(Handler.java:99)
    E/AndroidRuntime( 3579): at android.os.Looper.loop(Looper.java:130)
    E/AndroidRuntime( 3579): at android.app.ActivityThread.main(ActivityThread.java:3701)
    E/AndroidRuntime( 3579): at java.lang.reflect.Method.invokeNative(Native Method)
    E/AndroidRuntime( 3579): at java.lang.reflect.Method.invoke(Method.java:507)
    E/AndroidRuntime( 3579): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    E/AndroidRuntime( 3579): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
    E/AndroidRuntime( 3579): at dalvik.system.NativeStart.main(Native Method)
    W/ActivityManager( 237): Force finishing activity com.example.measureverify/.MainActivity

    验证代码:

        public class MenuListAdapter extends ArrayAdapter<ListItem> {
    private Activity context; public MenuListAdapter(Activity context) {
    super(context, 0);
    this.context = context;
    } public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
    if (unsafetyInflate) {
    // risk inflate case
    convertView = LayoutInflater.from(context).inflate(
    R.layout.custom_infowindow, null);
    } else {
    // safety inflate case(### Solution 1 ###)
    // The second parameter "mListView" provides a set of
    // LayoutParams values for root of the returned hierarchy
    convertView = LayoutInflater.from(context).inflate(
    R.layout.custom_infowindow, mListView, false);
    } // ### Solution 2 ###
    if (MainActivity.this.setLayoutParamsProgrammatically) {
    // NOTE: the layout params set here should be of the
    // {ParentView}.LayoutParams
    convertView
    .setLayoutParams(new ListView.LayoutParams(
    ListView.LayoutParams.WRAP_CONTENT,
    ListView.LayoutParams.WRAP_CONTENT));
    }
    Log.d(TAG, "case 1 parent:" + convertView.getParent() + " layoutParams:"
    + convertView.getLayoutParams());
    final int width = context.getWindow().getDecorView().getWidth();
    final int height = context.getWindow().getDecorView().getHeight();
    convertView.measure(width, height);
    MainActivity.this.mLayout = convertView;
    }
    final ListItem item = (ListItem) getItem(position);
    TextView title = (TextView) convertView.findViewById(R.id.title); title.setText("title " + Math.random() + item.prop_1);
    TextView snippet = (TextView) convertView.findViewById(R.id.snippet);
    snippet.setText("snippet " + Math.random() + item.prop_2);
    return convertView;
    } }
  2. 相关Android2.3.6 Framework层代码

    View.java中有一成员代表layout參数(子View对父View的请求,或者一种期望值,终于由整个View层次树决定)

        /**
    1623 * The layout parameters associated with this view and used by the parent
    1624 * {@link android.view.ViewGroup} to determine how this view should be
    1625 * laid out.
    1626 * {@hide}
    1627 */
    1628 protected ViewGroup.LayoutParams mLayoutParams;

    以及获取该成员的函数:

    4973    /**
    4974 * Get the LayoutParams associated with this view. All views should have
    4975 * layout parameters. These supply parameters to the <i>parent</i> of this
    4976 * view specifying how it should be arranged. There are many subclasses of
    4977 * ViewGroup.LayoutParams, and these correspond to the different subclasses
    4978 * of ViewGroup that are responsible for arranging their children.
    4979 * @return The LayoutParams associated with this view
    4980 */
    4981 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_")
    4982 public ViewGroup.LayoutParams getLayoutParams() {
    4983 return mLayoutParams;
    4984 }

    ViewGroup类中有一个方法用于将detached的View attach到父View:

    2352     * This method should be called only for view which were detached from their parent.
    2353 *
    2354 * @param child the child to attach
    2355 * @param index the index at which the child should be attached
    2356 * @param params the layout parameters of the child
    2357 *
    2358 * @see #removeDetachedView(View, boolean)
    2359 * @see #detachAllViewsFromParent()
    2360 * @see #detachViewFromParent(View)
    2361 * @see #detachViewFromParent(int)
    2362 */
    2363 protected void attachViewToParent(View child, int index, LayoutParams params) {
    2364 child.mLayoutParams = params; // 编者注:此处子View的mLayoutParams被设置
    2365
    2366 if (index < 0) {
    2367 index = mChildrenCount;
    2368 }
    2369
    2370 addInArray(child, index);
    2371
    2372 child.mParent = this;
    2373 child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN;
    2374
    2375 if (child.hasFocus()) {
    2376 requestChildFocus(child, child.findFocus());
    2377 }
    2378 }

    在ListView/GridView中都用调用此方法来设置好子View。

    ViewGroup类中同一时候还有另外一个更主流的方法(整个Layout被从xml中铺陈开attach到Window并变得有活力的过程中该方法会被调用到)

     private void addViewInner(View child, int index, LayoutParams params,
    1973 boolean preventRequestLayout) {
    1974
    1975 if (child.getParent() != null) {
    1976 throw new IllegalStateException("The specified child already has a parent. " +
    1977 "You must call removeView() on the child's parent first.");
    1978 }
    1979
    1980 if (!checkLayoutParams(params)) {
    1981 params = generateLayoutParams(params);
    1982 }
    1983
    1984 if (preventRequestLayout) {
    1985 child.mLayoutParams = params; // 编者注:直接不理会子View请求/意愿的case,直接由父View分配,强迫子View接受
    1986 } else {
    1987 child.setLayoutParams(params); // 编者注:温和一刀的做法。很体谅的设置给子View。究竟惬意不惬意,取决于子View自身
    1988 }
    1989
    1990 if (index < 0) {
    1991 index = mChildrenCount;
    1992 }
    1993
    1994 addInArray(child, index);
    1995
    1996 // tell our children
    1997 if (preventRequestLayout) {
    1998 child.assignParent(this);
    1999 } else {
    2000 child.mParent = this;
    2001 }
    2002
    2003 if (child.hasFocus()) {
    2004 requestChildFocus(child, child.findFocus());
    2005 }
    2006
    2007 AttachInfo ai = mAttachInfo;
    2008 if (ai != null) {
    2009 boolean lastKeepOn = ai.mKeepScreenOn;
    2010 ai.mKeepScreenOn = false;
    2011 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
    2012 if (ai.mKeepScreenOn) {
    2013 needGlobalAttributesUpdate(true);
    2014 }
    2015 ai.mKeepScreenOn = lastKeepOn;
    2016 }
    2017
    2018 if (mOnHierarchyChangeListener != null) {
    2019 mOnHierarchyChangeListener.onChildViewAdded(this, child);
    2020 }
    2021
    2022 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
    2023 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
    2024 }
    2025 }
    2026
    
    

    由以上代码片断综合可知,在一个View只从XML中Inflate出来未被attach到View层次树里边去的时候,View.mLayoutParams成员为空。

  3. RelativeLayout为什么会NullPointerException在onMeasure
    回到文章开头的StackTrace,同一时候參照RelativeLayout的onMeasure():
    426        if (isWrapContentWidth) {
    427 // Width already has left padding in it since it was calculated by looking at
    428 // the right of each child view
    429 width += mPaddingRight;
    430
    431 if (mLayoutParams.width >= 0) { // 编者注:该处为onMeasure方法中第一次使用到mLayoutParams的地方
    432 width = Math.max(width, mLayoutParams.width);
    433 }
    434
    435 width = Math.max(width, getSuggestedMinimumWidth());
    436 width = resolveSize(width, widthMeasureSpec);
    437
    438 if (offsetHorizontalAxis) {
    439 for (int i = 0; i < count; i++) {
    440 View child = getChildAt(i);
    441 if (child.getVisibility() != GONE) {
    442 LayoutParams params = (LayoutParams) child.getLayoutParams();

    不难看出,在RelativeLayout被add/attach到父View之前mLayoutParams成员为空。调用measure方法将导致上图标注处代码抛出空指针异常。

  4. 解决方式有两种
    a) 在measure之前显式设置LayoutParams(代表着对父View的Layout请求。必须是父View的内部LayoutParams类型)
    b) 自己主动设置LayoutParams的inflate方式
    请见代码:
         public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
    if (unsafetyInflate) {
    // risk inflate case
    convertView = LayoutInflater.from(context).inflate(
    R.layout.custom_infowindow, null);
    } else {
    // safety inflate case(### Solution 1 ###)
    // The second parameter "mListView" provides a set of
    // LayoutParams values for root of the returned hierarchy
    convertView = LayoutInflater.from(context).inflate(
    R.layout.custom_infowindow, mListView, false);
    } // ### Solution 2 ###
    if (MainActivity.this.setLayoutParamsProgrammatically) {
    // NOTE: the layout params set here should be of the
    // {ParentView}.LayoutParams
    convertView
    .setLayoutParams(new ListView.LayoutParams(
    ListView.LayoutParams.WRAP_CONTENT,
    ListView.LayoutParams.WRAP_CONTENT));
    }
    Log.d(TAG, "case 1 parent:" + convertView.getParent() + " layoutParams:"
    + convertView.getLayoutParams());
    final int width = context.getWindow().getDecorView().getWidth();
    final int height = context.getWindow().getDecorView().getHeight();
    convertView.measure(width, height);
    MainActivity.this.mLayout = convertView;
    }
    final ListItem item = (ListItem) getItem(position);
    TextView title = (TextView) convertView.findViewById(R.id.title); title.setText("title " + Math.random() + item.prop_1);
    TextView snippet = (TextView) convertView.findViewById(R.id.snippet);
    snippet.setText("snippet " + Math.random() + item.prop_2);
    return convertView;
    }

    完整project代码截图:

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ2ZlaTU4NDUyMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="Measure验证project截图">

  5. Android各个平台上这一问题的可复现性
    在查看多个版本号Android源代码后发现,Android 4.4_r1中已经针对该NullPointerException做了防范:
    539            if (mLayoutParams != null && mLayoutParams.width >= 0) {
    540 width = Math.max(width, mLayoutParams.width);
    541 }
    542
    543 width = Math.max(width, getSuggestedMinimumWidth());
    544 width = resolveSize(width, widthMeasureSpec);
    545
    546 if (offsetHorizontalAxis) {
    547 for (int i = 0; i < count; i++) {
    548 View child = getChildAt(i);
    549 if (child.getVisibility() != GONE) {
    550 LayoutParams params = (LayoutParams) child.getLayoutParams();
    551 final int[] rules = params.getRules(layoutDirection);
    552 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
    553 centerHorizontal(child, params, width);
    554 } else if (rules[ALIGN_PARENT_RIGHT] != 0) {
    555 final int childWidth = child.getMeasuredWidth();
    556 params.mLeft = width - mPaddingRight - childWidth;
    557 params.mRight = params.mLeft + childWidth;
    558 }
    559 }
    560 }
    561 }
    562 }

版权声明:本文博客原创文章。博客,未经同意,不得转载。

分析java.lang.NullPointerException thrown in RelativeLayout measure()的更多相关文章

  1. “java.lang.NullPointerException”异常分析

    1.父类定义的某个属性,没有被子类使用,或者在子类中,又重新定义一次. 2.因为调用了一个object的方法,且此object的reference为null:比如说:String a=null; // ...

  2. activity_main.xml: java.lang.NullPointerException

    1.错误描写叙述 eclipse.buildId=4.4.0.I20140606-1215 java.version=1.7.0_67 java.vendor=Oracle Corporation B ...

  3. java.lang.NullPointerException的可能原因及处理

    java.lang.NullPointerException的可能原因及处理 java.lang.NullPointerException具体意思是空指针异常,最常见的问题就是没有初始化. 字符串等数 ...

  4. 转载java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.spinner/com.example.spinner.MainActivity}: java.lang.NullPointerException

    今天学习Android开发突然遇到了这个问题,查阅了很多资料,并且对集中原因进行了分析. 错误信息字符串:java.lang.RuntimeException: Unable to start act ...

  5. CrashHandler: java.lang.NullPointerException

    08-29 20:33:47.305 20636-20636/com.tongyan.subway.inspect D/AndroidRuntime: Shutting down VM 08-29 2 ...

  6. java 空指针异常(java.lang.NullPointerException)

    在Java中对值为null的指针调用任何方法,就会引发空指针异常(java.lang.NullPointerException).空指针异常绝对 是Java中最难查找和调试的一种异常,你永远无法得到任 ...

  7. java.lang.NullPointerException&com.cb.action.LoginAction.execute(LoginAction.java:48)

    今天做一个Spring和Struts的融合,通过bean注入后,程序一跑起来,就报这个错误: java.lang.NullPointerException com.cb.action.LoginAct ...

  8. 安卓开发过程中空指针的问题Java.lang.NullPointerException

    最近做一个新闻客户端的应用,经常出现空指针的问题,我想一方面可能是自己水平有限,二是开发过程中有一些遗漏的地方.一般情况下新手出现空指针的概率较高.下面来总结一下经常出现的问题. 1.所谓的指针,就是 ...

  9. Scala操作Hbase空指针异常java.lang.NullPointerException处理

    Hbase版本:Hortonworks Hbase 1.1.2 问题描述:使用Scala操作Hbase时,发生空指针异常(java.lang.RuntimeException: java.lang.N ...

随机推荐

  1. ThinkPhp学习07

    原文:ThinkPhp学习07 简单CRUD操作 public function show() { $m=M('User'); // $arr=$m->find(2); //查找id=2的数据, ...

  2. TCP连接的建立(二)

    被动打开 SYN cookies TCP协议开辟了一个比較大的内存空间请求连接队列来存储连接请求块,当SYN请求不断添加,请求连接数目到达上限时,会致使系统丢弃SYN连接请求.SYN cookies技 ...

  3. NginX issues HTTP 499 error after 60 seconds despite config. (PHP and AWS)

    FROM: http://stackoverflow.com/questions/15613452/nginx-issues-http-499-error-after-60-seconds-despi ...

  4. Android获取设备採用的时间制式(12小时制式或24小时制式)

    /** * 获取设备採用的时间制式(12小时制式或者24小时制式) * 注意: * 在模拟器上获取的时间制式为空 */ private void getTime_12_24(Context conte ...

  5. [置顶] github简单使用

    git的介绍可以看这里   http://zh.wikipedia.org/wiki/GitHub 安装和使用参考的这个    http://www.cnblogs.com/cocowool/arch ...

  6. Eclipse 未开始 【Ubuntu】

    /usr/lib/eclipse/configuration/1408532831122.log : !SESSION 2014-08-20 19:07:11.055 ---------------- ...

  7. [品质生活] 舒适 Schick HYDRO 5剃须刀

    [品质生活] 舒适 Schick HYDRO 5剃须刀 [品质生活] 舒适 Schick HYDRO 5剃须刀

  8. Ipsec transport mode and turnnel mode

     隧道(tunnel)模式:用户的整个IP数据包被用来计算AH或ESP头,AH或ESP头以及ESP加密的用户数据被封装在一个新的IP数据包中.通常,隧道模式应用在两个安全网关之间的通讯. 传输(t ...

  9. 菜鸟学Java(十九)——WEB项目測试好帮手,Maven+Jetty

    做WEB开发,測试是一件非常费时间的事情.所以我们就应该用更简单.更快捷的方式进行測试.今天就向大家介绍一个轻量级的容器--jetty.j今天说的etty是Maven的一个插件jetty-maven- ...

  10. CSDN博客的一些问题(友好的吐槽)--后记,有一点点改进

    近期,CSDN博客真的非常不稳定,时常会出现503错误. 昨天.我发现自己的博客的訪问量仅仅有4万多,今天最终发现它变回原来的6万多了. 我写博客不是为了这个訪问量,可是,CSDN这点使用问题啦. 或 ...