Avoid passing null as the view root windowManager使用
来源:互联网 发布:淘宝村淘收费标准 编辑:程序博客网 时间:2024/06/03 06:24
Avoid passing null as the view root (needed to resolve layout parameters on the inflated layout's root element) 报错。
在使用windowmanager做弹窗的时候,会出现这个问题。只是一个警告,正常使用并不报错,代码如下:
LayoutInflater inflater = LayoutInflater.from(getApplication());//将布局文件填充到ViewmFloatLayout = (RelativeLayout) inflater.inflate(R.layout.result_windows, null);if(mFloatLayout.getParent() == null)winManager.addView(mFloatLayout, wmParams);出现这个问题的原因,有一篇文章讲的比较透彻,点击我!
总结一句话就是说,当我们使用LayoutInflater这个“填充器”填充result_windows这个布局View(文中为mFloatLayout)的时候,后面null为root根ViewGroup对象。也就是说,没有指定根对象。下面是第二个参数的解释:
root Optional view to be the parent of the generated hierarchy.一个可选的view对象,它是作为生成的对象的父对象。这是我的理解。LayoutInflater will automatically attempt to attach the inflated view to the supplied root. However, the framework has a check in place that if you pass null for the root it bypasses this attempt to avoid an application crash.
比较快速的修正这个警告的办法:
mFloatLayout = View.inflate(getApplicationContext(), R.layout.result_windows, null);//添加View填充--------------------------------if(mFloatLayout.getParent() == null)winManager.addView(mFloatLayout, wmParams);下面是使用static方法获取生成的View,警告消除,我们可以看一下,eclipse的参数提示:
root A view group that will be the parent. Used to properly inflate the layout_* parameters一看之下,貌似也没看明白,搜了点资料。发现其实没区别。View.inflate和Layoutinflater.inflate
/** * Inflate a view from an XML resource. This convenience method wraps the {@link * LayoutInflater} class, which provides a full range of options for view inflation. * * @param context The Context object for your activity or application. * @param resource The resource ID to inflate * @param root A view group that will be the parent. Used to properly inflate the * layout_* parameters. * @see LayoutInflater */ public static View inflate(Context context, int resource, ViewGroup root) { LayoutInflater factory = LayoutInflater.from(context); return factory.inflate(resource, root); }
那么看起来,警告是消除了,其实是没有检测到而已,并没有本质上的区别罢了。一篇介绍参数的博文:参数介绍
下面来一个介绍View实例化过程的文章:View实例化过程详解 ,这个文章需要一点耐心来看,总体来说,比自己理解要来的简单一些。
重点看一下,inflate这个方法以及ViewGroup类:
public View inflate(int resource, ViewGroup root) { return inflate(resource, root, root != null); } public View inflate(int resource, ViewGroup root, boolean attachToRoot) { /*可以看到通过resource id返回了一个XmlResourceParser,通过类名就可以猜测 这是一个xml的解析类。但点进去一看,发现它只是一个接口,它继承自 XmlPullParser用于pull方式解析xml的接口。和AttributeSet用于获取此view的所有属性。 那么需要能找到它的实现类。先看下面resource类。 */ XmlResourceParser parser = getContext().getResources().getLayout(resource); try { return inflate(parser, root, attachToRoot); //说实话,从这里开始没完没了的函数调用,我就不再往下贴了。。。 } finally { parser.close(); } } ............./** * 真正创建一个view的方法, * 此方法是用反射获取构造器来实例对象而不是直接new出来这是为了处于性能优化考虑, * 同一个类名的不同对象,可以直接得到缓存的构造器直接获取一个构造器对象实例。而不需要 * 重复进行new操作。 * * @param name 此View的全名 * @param prefix 前缀,值为 "android.view."其实就是是否包含包名 * @param attrs 此view的属性值,传递给此view的构造函数 */ public final View createView(String name, String prefix, AttributeSet attrs) throws ClassNotFoundException, InflateException { Constructor constructor = sConstructorMap.get(name); //缓存中是否已经有了一个构造函数 Class clazz = null; try { if (constructor == null) { //通过类名获得一个class对象 clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name); if (mFilter != null && clazz != null) { boolean allowed = mFilter.onLoadClass(clazz); if (!allowed) { failNotAllowed(name, prefix, attrs); } } //通过参数类型获得一个构造器,参数列表为context,attrs constructor = clazz.getConstructor(mConstructorSignature); sConstructorMap.put(name, constructor); //把此构造器缓存起来 } else { // If we have a filter, apply it to cached constructor if (mFilter != null) { // Have we seen this name before? Boolean allowedState = mFilterMap.get(name); if (allowedState == null) { // New class -- remember whether it is allowed clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name); boolean allowed = clazz != null && mFilter.onLoadClass(clazz); mFilterMap.put(name, allowed); if (!allowed) { failNotAllowed(name, prefix, attrs); } } else if (allowedState.equals(Boolean.FALSE)) { failNotAllowed(name, prefix, attrs); } } } Object[] args = mConstructorArgs; args[1] = attrs; //args[0]已经在前面初始好了。这里只要初始化args[1] return (View) constructor.newInstance(args); //通过反射new出一个对象。。大功告成 } catch (NoSuchMethodException e) { InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + (prefix != null ? (prefix + name) : name)); ie.initCause(e); throw ie; } catch (ClassNotFoundException e) { // If loadClass fails, we should propagate the exception. throw e; } catch (Exception e) { InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + (clazz == null ? "<unknown>" : clazz.getName())); ie.initCause(e); throw ie; } }
View的子类ViewGroup,可以简单理解为View的一个“组”,包含了一组View,其中重写了一个函数:
//哈哈,果然重写了此方法。其实就是在viewgroup包含的 //子view数组中进行遍历。那么view是什么时候被加入进 //viewgroup中的呢?如果是在代码中写,肯定是直接使用 //addView方法把view加入viewGroup。如果写在xml布局文件 //中,其实是在第二种方法中被加入view的。inflate加载父view //时会同时把其所有的子view加载完,同时addView到父view中 protected View findViewTraversal(int id) { if (id == mID) { return this; } final View[] where = mChildren; final int len = mChildrenCount; for (int i = 0; i < len; i++) { View v = where[i]; if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { v = v.findViewById(id); if (v != null) { return v; } } } return null; }
人家还是总结的不错的:
也就是说:假如root设置为null或者root!=nul但attachToRoot设置为false,则这个xml加载出来的view不会挂载到别的视图节点上去;当root!=null并且attachToRoot设置为true时,就会挂载上去,return为root当root!=nul但attachToRoot设置为false时,这个root用来view生成正确的params布局参数来match root。
这个是我结合前人的基础上的理解,所以,我这里填null,也就导致新生成的windows不会附加于任何View,它是直接面向屏幕的,这个也符合windowManager的特性:整个Android的窗口机制是基于一个叫做 WindowManager,这个接口可以添加view到屏幕,也可以从屏幕删除view。它面向的对象一端是屏幕,另一端就是View,直接忽略我们以前的Activity或者Dialog之类的,这个 WindowManager是全局的,整个系统就是这个唯一的,这也就是说,不可以new出来,它最好也不要依附于任何activity是最好的。
还是有很多不明白的地方,希望明白的朋友回一下。 T ~ T....
谢谢了!
- Avoid passing null as the view root windowManager使用
- Avoid passing null as the view root
- Avoid passing null as the view root ?
- Avoid passing null as the view root convertView = infalInflater.inflate(R.layout.list_item, null);
- LayoutInflater的错误用法(Avoid passing null as the view root )
- 关于LayoutInflater的错误用法(警告提示:Avoid passing null as the view root)
- Avoid passing null as the view root (needed to resolve layout parameters on the inflated layout's ro
- Avoid passing null as the view root (needed to resolve layout parameters on the inflated layout's r
- 【Android】使用WindowManager添加View
- android使用WindowManager显示自定义View
- QML: passing RichText as PlainText
- passing the word
- Passing the Message
- Passing the Message
- Passing the Message
- Passing Data between View Controllers
- Passing data between view controller.
- Passing Data between View Controllers
- 黑马程序员--设计模式之单例模式
- sencha touch2.x 自动提示配置 eclipse spket jsb
- DES 双向加密算法 DESUtil
- nginx源码安装
- Oracle触发器
- Avoid passing null as the view root windowManager使用
- 黑马程序员——C语言基础---C语言的基础语法
- AES 双向加密算法 AESUtil
- [require.js]初识require.js
- 数组指针与指针数组
- Extjs5 Tab标签右键单击菜单
- 后端开发程序员必知的开源库
- (三十五)控制器的生命周期循环
- Java中的加号“+”