当前位置: 首页 > 科技观察

探究LayoutInflater源码布局分析原理

时间:2023-03-16 01:54:26 科技观察

本文转载自微信公众号《Android开发编程》,作者Android开发编程。转载本文请联系Android开发编程公众号.前言在开发中,对于LayoutInflater的inflate()方法,其作用是将xml布局转换成对应的View对象,我们几乎每天都会用到;今天我们就来分析解释一下;1.什么是LayoutInflater?LayoutInflater的作用是将XML布局文件实例化成对应的View对象。您需要获取与当前Context相关联的标准LayoutInflater,并通过Activity.getLayoutInflater()或Context.getSystemService(Class)正确配置;@SystemService(Context.LAYOUT_INFLATER_SERVICE)publicabstractclassLayoutInflater{...}GetLayoutInflater1,View.inflate(...)publicstaticViewinflate(Contextcontext,@LayoutResintresource,ViewGrouproot){LayoutInflaterfactory=LayoutInflater.from(context);returnfactory.inflate(resource,root);}2、Activity#getLayoutInflater()Activity.class的源代码:publicclassActivityextends...........@NonNullpublicLayoutInflatergetLayoutInflater(){returngetWindow().getLayoutInflater();}................@NonNullpublicLayoutInflatergetLayoutInflater(){returngetWindow().getLayoutInflater();}......finalvoidattach(.....){...mWindow=newPhoneWindow(this,window,activityConfigCallback);.......}......}PhoneWindow源代码:publicPhoneWindow(Contextcontext){super(context);mLayoutInflater=LayoutInflater.from(context);}3、PhoneWindow#getLayoutInflater()privateLayoutInflatemLayoutInflater;publicPhoneWindow(Contextcontext){super(context);mLayoutInflater=LayoutInflater.from(context);}publicLayoutInflatergetLayoutInflater(){returnmLayoutInflater;}4、LayoutInflater#from(Context)@SystemService(Context.LAYOUT_INFLATER_SERVICE)publicabstractclassLayoutInflater{...../***从给定的上下文中获取LayoutInflater.*/publicstaticLayoutInflaterfrom(Contextcontext){LayoutInflaterLayoutInflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);if(LayoutInflater==null){thrownewAssertionError("LayoutInflaternotfound.");}returnLayoutInflater;}......}二、源码分析1、LayoutInflater#inflate(...)调用inflate()进行布局解析publicViewinflate(@LayoutResintresource,@NullableViewGrouproot,booleanattachToRoot){finalResourcesres=getContext().getResources();1.解析预测的布局Viewview=tryInflatePre已编译(资源、资源、根、attachToRoot);如果(视图!=null){returnview;}2。构建XmlPull解析器XmlResourceParserparser=res.getLayout(resource);try{3.执行解析returninflate(parser,root,attachToRoot);}finally{parser.close();}}tryInflatePrecompiled(...)是解析预编译布局;构造XmlPull解析器XmlResourceParser进行解析,这是解析的主要过程2.inflatepublicViewinflate(XmlPullParserparser,@NullableViewGrouproot,booleanattachToRoot){1.结果变量Viewresult=root;2.最外层标签finalStringname=parser.getName();3.if(TAG_MERGE.equals(name)){3.1异常if(root==null||!attachToRoot){thrownewInflateException("canbeusedonlywithvalid"+"ViewGrouprootandattachToRoot=true");}3.2递归执行解析rInflate(parser,root,inflaterContext,attrs,false);}else{4.1创建最外层ViewfinalViewtemp=createViewFromTag(root,name,inflaterContext,attrs);ViewGroup.LayoutParamsparams=null;if(root!=null){4.2创建匹配的LayoutParamsparams=root.generateLayoutParams(attrs);if(!attachToRoot){4.3如果attachToRoot为false,设置LayoutParamstemp.setLayoutParams(params);}}5.以temp为根,递归执行解析rInflateChildren(parser,temp,attrs,true);6.attachToRoot为真,addView()if(root!=null&&attachToRoot){root.addView(temp,params);}7.root为空或attachToRoot为假,返回tempif(root==null||!attachToRoot){result=temp;}}returnresult;}->3.2voidrInflate(XmlPullParserparser,Viewparent,Contextcontext,AttributeSetattrs,booleanfinishInflate){while(解析器未完成){if(TAG_INCLUDE.equals(name)){1)if(parser.getDepth()==0){thrownewInflateException("cannotbetherootelement");}parseInclude(parser,context,parent,attrs);}elseif(TAG_MERGE.equals(name)){2)thrownewInflateException("mustbetherootelement");}else{3)创建视图finalViewview=createViewFromTag(parent,name,context,attrs);finalViewGroupviewGroup=(ViewGroup)parent;finalViewGroup.LayoutParamsparams=viewGroup.generateLayoutParams(attrs);4)递归rInflateChildren(parser,view,attrs,true);5)添加到视图树viewGroup.addView(view,params);}}}->5.递归执行解析finalvoidrInflateChildren(XmlPullParserparser,Viewparent,AttributeSetattrs,booleanfinishInflate)throwsXmlPullParserException,IOException{rInflate(parser,parent,parent.getContext(),attrs,finishInflate);}3、createViewFromTagcreateViewFromTag(),它由创建View对象ViewcreateViewFromTag(Viewparent,Stringname,Contextcontext,AttributeSetattrs,booleanignoreThemeAttr){if(name.equals("view")){name=attrs.getAttributeValue(null,"class");}//Applyathemwrapper,ifallowedandoneisspecified.if(!ignoreThemeAttr){finalTypedArrayta=context.obtainStyledAttributes(attrs,ATTRS_THEME);finalintthemeResId=ta.getResourceId(0,0);if(themeResId!=0){context=newContextThemeWrapper(context,themeResId);}ta.recycle();}if(name.equals(TAG_1995)){//Let'spartylikeit's1995!returnnewBlinkLayout(context,attrs);}try{Viewview;if(mFactory2!=null){//①有mFactory2,则调用mFactory2的onCreateView方法view=mFactory2.onCreateView(parent,name,context,attrs);}elseif(mFactory!=null){//②如果有mFactory,则调用mFactory的onCreateView方法view=mFactory.onCreateView(name,context,attrs);}else{view=null;}if(view==null&&mPrivateFactory!=null){//③如果有mPrivateFactory,则调用mPrivateFactory的onCreateView方法步骤显示没有三个工厂,所以开始创建ViewfinalObjectlastContext=mConstructorArgs[0];mConstructorArgs[0]=context;try{if(-1==name.indexOf('.')){//⑤如果View如果名称中不包含'.',则表示它是一个系统控件,'android.view.'view=onCreateView(parent,name,attrs);}else{//⑥如果名称中包含'.',则直接调用createView方法,onCreateView也会调用createViewview=createView(name,null,attrs);}}finally{mConstructorArgs[0]=lastContext;}}returnview;}catch(InflateExceptione){throwe;}}createViewFromTag方法比较简单,先尝试通过Factory创建View;如果没有Factory,则通过createView创建View;on{Constructorconstructor=sConstructorMap.get(name);if(constructor!=null&&!verifyClassLoader(constructor)){constructor=null;sConstructorMap.remove(name);}Classclazz=null;try{Trace.traceBegin(Trace.TRACE_TAG_VIEW,name);if(constructor==null){//Classnotfoundinthecache,seifit'sreal,andtrytoadditclazz=mContext.getClassLoader().loadClass(prefix!=null?(prefix+name):name).asSubclass(View.class);if(mFilter!=null&&clazz!=null){booleanallowed=mFilter.onLoadClass(clazz);if(!allowed){failNotAllowed(name,prefix,attrs);}}//①反射获取这个View的构造器constructor=clazz.getConstructor(mConstructorSignature);constructor.setAccessible(true);//②缓存构造器sConstructorMap.put(name,constructor);}else{//Ifwehaveafilter,applyittocachedconstructorif(mFilter!=null){//Haveweseenthisnamebefore?BooleanallowedState=mFilterMap.get(name);if(allowedState==null){//Newclass--rememberwhetheritisallowedclazz=mContext.getClassLoader().loadClass(prefix!=null?(prefix+name):name).asSubclass(View.class);booleanallowed=clazz!=null&&mFilter.onLoadClass(clazz);mFilterMap.put(name,allowed);if(!allowed){failNotAllowed(名称、前缀、属性);}}elseif(allowedState.equals(Boolean.FALSE)){failNotAllowed(名称、前缀、属性);}}}ObjectlastContext=mConstructorArgs[0];if(mConstructorArgs[0]==null){//Fillinthecontextifnotalreadywithininflation.mConstructorArgs[0]=mContext;}Object[]args=mConstructorArgs;args[1]=attrs;//③使用反射创建View对象,这样就创建了一个ViewfinalViewview=constructor.newInstance(args);if(viewinstanceofViewStub){//UsethesamecontextwheninflatingViewStublater.finalViewStubviewStub=(ViewStub)view;viewStub.setLayoutInflater(cloneInContext((Context)args[0]));}mConstructorArgs[0]=lastContext;returnview;}catch(ClassCastExceptione){}}createView方法也比较简单,通过反射创建的View对象;4.Factory2接口Factory2可以拦截实例化View的步骤,LayoutInflater中有两个方法可以设置:方法一:publicvoidsetFactory2(Factory2factory){if(mFactorySet){重点:不要重复设置thrownewIllegalStateException("AfactoryhasalreadybeensensetonthisLayoutInflater");}if(factory==null){thrownewNullPointerException("Givenfactorycannotbenull");}mFactorySet=true;if(mFactory==null){mFactory=mFactory2=factory;}else{mMfactory=mFactoryerger2=newFactory(factory,factory,mFactory,mFactory2);}}方法二@hidepublicvoidsetPrivateFactory(Factory2factory){if(mPrivateFactory==null){mPrivateFactory=factory;}else{mPrivateFactory=newFactoryMerger(factory,factory,mPrivateFactory,mPrivate}Factory)使用setFactory2()和setPrivateFactory()设置Factory2接口(拦截器),其中同一个LayoutInflater的setFactory2()不能重复设置,setPrivateFactory()是隐藏方法;综上所述,View的标签是通过XMLPull解析得到的;通过标签反射的方式创建View对象;如果是ViewGroup,会遍历子View,重复上面的步骤,然后添加到父View;与之相关的几个方法:inflate-->rInflate-->createViewFromTag--》createView;Factory2是一个非常实用的接口,需要掌握通过setFactory2()拦截布局解析的技巧;

最新推荐
猜你喜欢