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