网友通过本文主要向大家介绍了androidxml,android xml view,android xml解析,android xml布局,android xml注释等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
Android XML中引用自定义内部类view的四个why,androidxml
今天碰到了在XML中应用以内部类形式定义的自定义view,结果遇到了一些坑。虽然通过看了一些前辈写的文章解决了这个问题,但是我看到的几篇都没有完整说清楚why,于是决定做这个总结。
使用自定义内部类view的规则
本文主要是总结why,所以先把XML布局文件中引用内部类的自定义view的做法摆出来,有四点:
布局加载流程主要代码
首先,XML布局文件的加载都是使用LayoutInflater来实现的,通过这篇文章的分析,我们知道实际使用的LayoutInflater类是其子类PhoneLayoutInflater,然后通过这篇文章的分析,我们知道view的真正实例化的关键入口函数是createViewFromTag这个函数,然后通过createView来真正实例化view,下面便是该流程用到的关键函数的主要代码:
1 final Object[] mConstructorArgs = new Object[2]; 2 3 static final Class<?>[] mConstructorSignature = new Class[] { 4 Context.class, AttributeSet.class}; 5 6 //... 7 8 /** 9 * Creates a view from a tag name using the supplied attribute set. 10 * <p> 11 * <strong>Note:</strong> Default visibility so the BridgeInflater can 12 * override it. 13 * 14 * @param parent the parent view, used to inflate layout params 15 * @param name the name of the XML tag used to define the view 16 * @param context the inflation context for the view, typically the 17 * {@code parent} or base layout inflater context 18 * @param attrs the attribute set for the XML tag used to define the view 19 * @param ignoreThemeAttr {@code true} to ignore the {@code android:theme} 20 * attribute (if set) for the view being inflated, 21 * {@code false} otherwise 22 */ 23 View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, 24 boolean ignoreThemeAttr) { 25 //**关键1**// 26 if (name.equals("view")) { 27 name = attrs.getAttributeValue(null, "class"); 28 } 29 30 // Apply a theme wrapper, if allowed and one is specified. 31 if (!ignoreThemeAttr) { 32 final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME); 33 final int themeResId = ta.getResourceId(0, 0); 34 if (themeResId != 0) { 35 context = new ContextThemeWrapper(context, themeResId); 36 } 37 ta.recycle(); 38 } 39 40 if (name.equals(TAG_1995)) { 41 // Let's party like it's 1995! 42 return new BlinkLayout(context, attrs); 43 } 44 45 try { 46 View view; 47 if (mFactory2 != null) { 48 view = mFactory2.onCreateView(parent, name, context, attrs); 49 } else if (mFactory != null) { 50 view = mFactory.onCreateView(name, context, attrs); 51 } else { 52 view = null; 53 } 54 55 if (view == null && mPrivateFactory != null) { 56 view = mPrivateFactory.onCreateView(parent, name, context, attrs); 57 } 58 59 if (view == null) { 60 final Object lastContext = mConstructorArgs[0]; 61 mConstructorArgs[0] = context; 62 try { 63 if (-1 == name.indexOf('.')) { 64 //**关键2**// 65 view = onCreateView(parent, name, attrs); 66 } else { 67 //**关键3**// 68 view = createView(name, null, attrs); 69 } 70 } finally { 71 mConstructorArgs[0] = lastContext; 72 } 73 } 74 75 return view; 76 } 77 //后面都是catch,省略 78 } 79 80 protected View onCreateView(View parent, String name, AttributeSet attrs) 81 throws ClassNotFoundException { 82 return onCreateView(name, attrs); 83 } 84 85 protected View onCreateView(String name, AttributeSet attrs) 86 throws ClassNotFoundException { 87 return createView(name, "android.view.", attrs); 88 } 89 90 /** 91 * Low-level function for instantiating a view by name. This attempts to 92 * instantiate a view class of the given <var>name</var> found in this 93 * LayoutInflater's ClassLoader. 94 * 95