LayoutInflater

1.Context获取LayoutInflater的过程

常见的LayoutInflater的使用方式:

	LayoutInflater.form(context).inflate(layoutId, null);

这个方法实际上是调用了context的系统服务,获取了一个LayoutInfalter:

	public static Layout form(Context context){
		return (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

这里实际调用了ContextImpl类的getSystemService方法:Context

class ContextImpl extends Context {
	private static final HashMap<String,ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<>();

	public Object getSystemService(String name){
		ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
		return fetcher == null ? null : fetcher.getService(this);
	}
	
	//静态代码段注册LayoutInflater服务,第一次加载ContextImpl时会执行,且只执行一次
	static {
		refisterService(LAYOUT_INFLATER_SERVICE,new ServiceFetcher(){
			public Object createService(ContextImpl ctx){
				return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
			}
		});
	}
	
	static class ServiceFercher {
		public Object getService(ContextImpl ctx){
			ArrayList<Object> cache = ctx.mServiceCache;
			//缓存中有这个service就从缓存中拿
			service = cache.get(mContextCacheIndex);
			if(service != null){
				return service;
			}
			//缓存中没有这个service就创建一个,放入缓存并返回
			service = creatService(cxt);
			cache.set(mContextCacheIndex,service);
			return service;
		}
	}
}

从上面的代码可以看出,每个不同的Context对应了不同的ContextImpl,得到的LayoutInflater也是不同的,同一个Context多次获取LayoutInflater得到的是同一个对象;

InflaterLayout通过PolicyManager创建,实际上PolicyManager是个代理类,实际创建由Policy执行:

	public class Policy implements IPolicy {
		public LayoutInflater makeNewLayoutInflater(Context context) {
			//从这里可以知道LayoutInflater的实现类是PhoneLayoutInflater
			return new PhoneLayoutInflater(context);
		}
	}
2.Fragment中的LayoutInflater:

Fragment是被FragmentManager管理的,Fragment的生命周期方法在moveToState中被调用:

//className = FragmentManager
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {
	if (f.mState <= newState) {
		switch (f.mState) {
		 	case Fragment.INITIALIZING:
		 		 f.onAttach(mHost.getContext());
		 	case Fragment.CREATED:
			 	if (f.mState > CREATED) {
			 		...
			 		//这里获取了一个LayoutInflater 
			 		LayoutInflater inflater = f.performGetLayoutInflater(f.mSavedFragmentState)
					f.mView = f.performCreateView(inflater, container, f.mSavedFragmentState);
				}
		}
	}
}

Fragment获取LayoutInflater的过程:

//className = Fragment
public LayoutInflater getLayoutInflater(Bundle savedFragmentState) {
	//mHost是一个FragmentHostCallback,或者是Activity
	LayoutInflater result = mHost.onGetLayoutInflater();
    getChildFragmentManager(); 
    //这里为获取到的LayoutInflater添加了Factory2
    LayoutInflaterCompat.setFactory2(result, mChildFragmentManager.getLayoutInflaterFactory());
    return result;
}

//className = FragmentHostCallback
public LayoutInflater onGetLayoutInflater() {
     return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
//className = Activity
public LayoutInflater onGetLayoutInflater() {
     final LayoutInflater result = Activity.this.getLayoutInflater();
     if (onUseFragmentManagerInflaterFactory()) {
          return result.cloneInContext(Activity.this);
     }
     return result;
}
3.LayoutInflater创建View的过程

LayoutInflater是一个抽象类,它的inflat方法可以把xml文件转化为一个View:

	//class = LayoutInflater
	//这个方法主要是为了识别加载xml文件的根视图
	//attachToRoot为true的含义是,把新解析出来的View添加到root中作为它的childView
	//attachToRoot为false的含义是,只采用root的LayoutParams作为测量依据
	public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot){
		//这里主要解析了一个Xml文件
		//首先解析到rootView,然后解析各个子View,并把它们添加到rootView,最后返回rootView
		synchronized (mConstructorArgs) {
            //声明了View result = root,且最终返回值为result
            View result = root;
            int type;
            final String name = parser.getName();
            if (TAG_MERGE.equals(name)) {
               	//...处理merge标签
            } else {
                View temp = createViewFromTag(root, name, attrs);
                ViewGroup.LayoutParams params = null;
                if (root != null && !attachToRoot) {
                     //root非空,且不attachToRoot,为temp设置一个LayoutParams并返回,这是最常用的分支
                     temp.setLayoutParams(root.generateLayoutParams(attrs));
                }
                rInflate(parser, temp, attrs, true);
			    //root非空,且attachToRoot,把新建的view设置为root的子View
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }
		        //root为空,且不关联到root,返回temp(这里没有为temp设置LayoutParams)
                if (root == null || !attachToRoot) {
                    result = temp;
                }
             }
         }
         return result;
     }
  View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, 
   				boolean ignoreThemeAttr) {
   		...
		
		//这里有多种办法创建一个View
		//优先级为:Factory2 -> Factory -> mPrivateFactory -> Layoutnflater自己的方法
		//如果要改变View的实现可以考虑为Layoutnflater添加Factory从而绕过Layoutnflater自己的实现
        try {
            View view;
            if (mFactory2 != null) {
                view = mFactory2.onCreateView(parent, name, context, attrs);	//用Factory2创建View
            } else if (mFactory != null) {
                view = mFactory.onCreateView(name, context, attrs);				//用Factory创建View
            } else {
                view = null;
            }

            if (view == null && mPrivateFactory != null) {						//用PrivateFactory创建View
                view = mPrivateFactory.onCreateView(parent, name, context, attrs);	
            }

            if (view == null) {													//用Inflater自己的方法创建View
                if (-1 == name.indexOf('.')) {
                	//创建Android原生的View(android.view包下面的view)
                    view = onCreateView(parent, name, attrs);
                } else {
                    //创建自定义View或者依赖包中的View(xml中声明的是全路径)
                    view = createView(name, null, attrs);
                }
            }
            return view;
        } 
   }
public final View createView(String name, String prefix, AttributeSet attrs)
            throws ClassNotFoundException, InflateException {
        //根据name获取View缓存
        Constructor<? extends View> constructor = sConstructorMap.get(name);
        Class<? extends View> clazz = null;
        try {
            if (constructor == null) {
                //缓存为空就创建一个ViewConstructor并加入缓存
                //这里需要用控件的全名,例如在xml文件我们声明<TextView/>
                //那么这里name就是TextView, prefix就是android.widget.
                clazz = mContext.getClassLoader().loadClass(
                        prefix != null ? (prefix + name) : name).asSubclass(View.class);

                if (mFilter != null && clazz != null) {
                    boolean allowed = mFilter.onLoadClass(clazz);
                    if (!allowed) {
                        failNotAllowed(name, prefix, attrs);
                    }
                }
                constructor = clazz.getConstructor(mConstructorSignature);
                constructor.setAccessible(true);
                sConstructorMap.put(name, constructor);
            } else {
                if (mFilter != null) {
                    Boolean allowedState = mFilterMap.get(name);
                    if (allowedState == null) {
                        clazz = mContext.getClassLoader().loadClass(
                                prefix != null ? (prefix + name) : name).asSubclass(View.class);

                        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);
                    }
                }
            }
			//获取构造View所需要的参数,包括args[0]=Context,和args[1]=Attribuset
            Object lastContext = mConstructorArgs[0];
            if (mConstructorArgs[0] == null) {
                mConstructorArgs[0] = mContext;
            }
            Object[] args = mConstructorArgs;
            args[1] = attrs;
			//反射调用View(Context,Attribuset)创建一个View,这里的args中包含两个参数,即context和attrs
			//这也就说明了为什么自定义View时要实现View(Context,Attribuset)两个构造方法
            final View view = constructor.newInstance(args);
            if (view instanceof ViewStub) {
                final ViewStub viewStub = (ViewStub) view;
                viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
            }
            mConstructorArgs[0] = lastContext;
            return view;
        } catch (Exception e) {
           
        } 
    }
}

总结:
1.Inflate参数:
Inflate(resId , null ) 只创建temp ,返回temp
Inflate(resId , parent, false )创建temp,然后执行temp.setLayoutParams(params);返回temp
Inflate(resId , parent, true ) 创建temp,然后执行root.addView(temp, params);最后返回root
2.创建View的调用链:
inflate(int , ViewGroup , boolean)中通过Resource.getLayout(resource)将resource转换为XmlResourceParser
inflate(XmlResourceParser, ViewGroup , boolean)中调用了createViewFromTag方法创建View
createViewFromTag依据优先顺序Factory2 -> Factory -> mPrivateFactory -> Layoutnflater.createView创建View
createView调用View的二参构造方法创建View

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值