前文http://blog.csdn.net/sahadev_/article/details/49072045虽然讲解了LayoutInflate的整个过程,但是其中很多地方是不准确不充分的,这一节就详细讲一下我们上一节遗留的细节问题,我们遗留的问题有这些:
1.在PhoneWindow的setContentView里我们看到了一个mLayoutInflater对象,我们还没清楚它从哪来?
2.mLayoutInflater对象后来所调用的那些方法有没有被重载?
3.mFactory,mFactory2, mPrivateFactory这三个对象是否不为空?如果系统默认给它设置了值,那么后来生成的View是不是就是通过它们来设置的呢?
好,接下来就让我们一起把这些问题解开:
1. 我们先来看看mLayoutInflater从哪来,我们推测它极有可能和我们一样是使用这样的方式得来的:
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); }
我们知道getSystemService其实调用的就是ContextImpl的方法,ContextImpl是Context的具体实现类,我们进入ContextImpl的getSystemService中一探究竟:
public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); }
static { ... registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext()); }}); ... }
public LayoutInflater makeNewLayoutInflater(Context context) { return new PhoneLayoutInflater(context); }噢,原来所有的工作都是它在干啊!到这里,我们第一个问题就清楚了。
2.mLayoutInflater对象后来所调用的那些方法有没有被重载?其实这个问题我们直接进PhoneLayoutInflater中就可以知道答案:
/** Override onCreateView to instantiate names that correspond to the widgets known to the Widget factory. If we don't find a match, call through to our super class. */ @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { for (String prefix : sClassPrefixList) { try { View view = createView(name, prefix, attrs); if (view != null) { return view; } } catch (ClassNotFoundException e) { // In this case we want to let the base class take a crack // at it. } } return super.onCreateView(name, attrs); }
我们可以看到这个方法内部在遍历一个字符串数组,这个字符串数组被定义在类里:
private static final String[] sClassPrefixList = { "android.widget.", "android.webkit.", "android.app." };
在上一篇文章当中,我请大家在onCreateView中注意调用createView方法的第二个参数是"android.view.",这里被重写,看来是不满足了,子类实现了更为强大的功能,支持了更多的包进行加载,它这个过程一直在尝试去创建View,直到成功。好,我们第二个问题也解决完了。
3.mFactory,mFactory2, mPrivateFactory这三个对象是否不为空?看来这个问题我们就都知道了,PhoneLayoutInflater在构造的时候调用的是:
public PhoneLayoutInflater(Context context) { super(context); }