分析java.lang.NullPointerException thrown in RelativeLayout measure()
- 典型的再现环境
模型: 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;
} } - 相关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成员为空。
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方法将导致上图标注处代码抛出空指针异常。
解决方式有两种
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截图">
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()的更多相关文章
- “java.lang.NullPointerException”异常分析
1.父类定义的某个属性,没有被子类使用,或者在子类中,又重新定义一次. 2.因为调用了一个object的方法,且此object的reference为null:比如说:String a=null; // ...
- 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 ...
- java.lang.NullPointerException的可能原因及处理
java.lang.NullPointerException的可能原因及处理 java.lang.NullPointerException具体意思是空指针异常,最常见的问题就是没有初始化. 字符串等数 ...
- 转载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 ...
- CrashHandler: java.lang.NullPointerException
08-29 20:33:47.305 20636-20636/com.tongyan.subway.inspect D/AndroidRuntime: Shutting down VM 08-29 2 ...
- java 空指针异常(java.lang.NullPointerException)
在Java中对值为null的指针调用任何方法,就会引发空指针异常(java.lang.NullPointerException).空指针异常绝对 是Java中最难查找和调试的一种异常,你永远无法得到任 ...
- java.lang.NullPointerException&com.cb.action.LoginAction.execute(LoginAction.java:48)
今天做一个Spring和Struts的融合,通过bean注入后,程序一跑起来,就报这个错误: java.lang.NullPointerException com.cb.action.LoginAct ...
- 安卓开发过程中空指针的问题Java.lang.NullPointerException
最近做一个新闻客户端的应用,经常出现空指针的问题,我想一方面可能是自己水平有限,二是开发过程中有一些遗漏的地方.一般情况下新手出现空指针的概率较高.下面来总结一下经常出现的问题. 1.所谓的指针,就是 ...
- Scala操作Hbase空指针异常java.lang.NullPointerException处理
Hbase版本:Hortonworks Hbase 1.1.2 问题描述:使用Scala操作Hbase时,发生空指针异常(java.lang.RuntimeException: java.lang.N ...
随机推荐
- 《c陷阱与缺陷》笔记--移位运算
#include <stdio.h> int main(void){ int a = 2; a >> 32; a >> -1; a << 32; a & ...
- 黑客白皮书:如何成为一名黑客(附FAQ)
内容一览 为什么会有这份文档? 什么是黑客? 黑客应有的态度 黑客的基本技能 黑客文化中的地位 黑客和书呆子(Nerd)的联系 风格的意义 其它资源 FAQ(常问问题解答) 作为Jargon Fi ...
- 运行Dos命令并得到dos的输出文本(使用管道函数CreatePipe和PeekNamedPipe)
function RunDOS(const CommandLine: string): string;var HRead, HWrite: THandle; StartInfo: TStartup ...
- mysqladmin在SuSE linux系统中--sleep參数使用不准确问题
我们都知道,在MySQL中.能够使用mysqladmin命令的extended-status选项来查看MySQL的执行状态,比方获取我们经常关注的几个值: # mysqladmin -uroot -p ...
- UVA 1386 - Cellular Automaton(循环矩阵)
UVA 1386 - Cellular Automaton option=com_onlinejudge&Itemid=8&page=show_problem&category ...
- 奋斗的孩子的TableView(三篇文章)
http://blog.sina.com.cn/s/blog_a6fb6cc90101i8it.html http://blog.sina.com.cn/s/blog_a6fb6cc90101hhse ...
- java基础---->摘要算法的介绍 (转)
数据摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名.数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密.数据摘要算法也被称为哈希(Hash)算法. ...
- 上Https 和 http 差分
HTTPS 和 HTTP 差协议 超文本传输协定HTTP 对于web 浏览器和现场服务之间传递消息,HTTP 以纯文本协议 发送内容 无论不提供数据加密方法 假设拦截攻击web 浏览器和网站serve ...
- [置顶] vs2008 编译adb 支持4.2 android 系统(增加push 命令的进度)
QQ: 2506314894 本想晚些时候放出来的,但是按捺不住啊,所以修改了之后就立即放出来了.先说明一下,这次用的adb 的源码比较新的,用的vs2008 编译出来,只有一个exe 文件,直接就可 ...
- PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors()
PostgreSQL代码分析,查询优化部分. 这里把规范谓词表达式的部分就整理完了,阅读的顺序例如以下: 一.PostgreSQL代码分析,查询优化部分,canonicalize_qual 二.Pos ...