从源码的角度说说Activity的setContentView的原理(二)
前文http://blog.csdn.net/sahadev_/article/details/49072045雖然講解了LayoutInflate的整個(gè)過程,但是其中很多地方是不準(zhǔn)確不充分的,這一節(jié)就詳細(xì)講一下我們上一節(jié)遺留的細(xì)節(jié)問題,我們遺留的問題有這些:
1.在PhoneWindow的setContentView里我們看到了一個(gè)mLayoutInflater對(duì)象,我們還沒清楚它從哪來?
2.mLayoutInflater對(duì)象后來所調(diào)用的那些方法有沒有被重載?
3.mFactory,mFactory2,?mPrivateFactory這三個(gè)對(duì)象是否不為空?如果系統(tǒng)默認(rèn)給它設(shè)置了值,那么后來生成的View是不是就是通過它們來設(shè)置的呢?
好,接下來就讓我們一起把這些問題解開:
1. 我們先來看看mLayoutInflater從哪來,我們推測(cè)它極有可能和我們一樣是使用這樣的方式得來的:
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
但,這僅僅是推測(cè),我們要看到實(shí)際的代碼:
public PhoneWindow(Context context) {super(context);mLayoutInflater = LayoutInflater.from(context);}
通過查看源碼我們可以得知,在 PhoneWindow的構(gòu)造方法里是LayoutInflater.from(context);的方式對(duì)mLayoutInflater對(duì)象進(jìn)行了初始化,看來,它也是和我們一樣使用了同一個(gè)系統(tǒng)提供的LayoutInflater對(duì)象,那么,系統(tǒng)提供的這個(gè)LayoutInflater對(duì)象是在哪被構(gòu)造和添加進(jìn)去的呢?這我們就需要去Context.getSystemService方法里一探究竟了:
我們知道getSystemService其實(shí)調(diào)用的就是ContextImpl的方法,ContextImpl是Context的具體實(shí)現(xiàn)類,我們進(jìn)入ContextImpl的getSystemService中一探究竟:
public Object getSystemService(String name) {ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);return fetcher == null ? null : fetcher.getService(this);}
好,看來所有的服務(wù)都是通過SYSTEM_SERVICE_MAP取出來的,那么我們看看這些服務(wù)什么時(shí)候被添加進(jìn)去的,在 ContextImpl這個(gè)類中我們看到有個(gè)靜態(tài)方法:
private static void registerService(String serviceName, ServiceFetcher fetcher) {if (!(fetcher instanceof StaticServiceFetcher)) {fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;}SYSTEM_SERVICE_MAP.put(serviceName, fetcher);}
看來所有的服務(wù)都是通過它加進(jìn)去的,那什么時(shí)候加進(jìn)去的呢,我們?cè)谶@個(gè)類當(dāng)中可以看到一段很長(zhǎng)的靜態(tài)代碼塊,在代碼塊中發(fā)現(xiàn)了它的身影:
static {...registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {public Object createService(ContextImpl ctx) {return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());}});...}
好吧,看來系統(tǒng)系統(tǒng)的 LayoutInflater的對(duì)象其實(shí)是由PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());這個(gè)方法構(gòu)造出來的(又是PolicyManager,我們剛才看到它執(zhí)行的makeNewWindow,看來它做了不少事情), 不用多說,我們直接進(jìn)入Policy中看(不清楚這個(gè)過程的同學(xué)可以直接看這里 http://blog.csdn.net/sahadev_/article/details/49072045 ):
public LayoutInflater makeNewLayoutInflater(Context context) {return new PhoneLayoutInflater(context);}噢,原來所有的工作都是它在干啊!到這里,我們第一個(gè)問題就清楚了。
2.mLayoutInflater對(duì)象后來所調(diào)用的那些方法有沒有被重載?其實(shí)這個(gè)問題我們直接進(jìn)PhoneLayoutInflater中就可以知道答案:
/** Override onCreateView to instantiate names that correspond to thewidgets 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);}
噢,原來我們?cè)谏弦黄恼庐?dāng)中分析的onCreateView方法是沒有被調(diào)用的,那看來父類中的這個(gè)方法的功能是不滿足的,那我們分析分析被復(fù)寫的這個(gè)方法:
我們可以看到這個(gè)方法內(nèi)部在遍歷一個(gè)字符串?dāng)?shù)組,這個(gè)字符串?dāng)?shù)組被定義在類里:
private static final String[] sClassPrefixList = {"android.widget.","android.webkit.","android.app."};
在上一篇文章當(dāng)中,我請(qǐng)大家在onCreateView中注意調(diào)用createView方法的第二個(gè)參數(shù)是"android.view.",這里被重寫,看來是不滿足了,子類實(shí)現(xiàn)了更為強(qiáng)大的功能,支持了更多的包進(jìn)行加載,它這個(gè)過程一直在嘗試去創(chuàng)建View,直到成功。好,我們第二個(gè)問題也解決完了。
3.mFactory,mFactory2,?mPrivateFactory這三個(gè)對(duì)象是否不為空?看來這個(gè)問題我們就都知道了,PhoneLayoutInflater在構(gòu)造的時(shí)候調(diào)用的是:
public PhoneLayoutInflater(Context context) {super(context);}
后來也沒有對(duì)它進(jìn)行什么設(shè)置,所以看來它們都是空,這里這3個(gè)對(duì)象是開放給我們使用的,我們可以在View被加載的時(shí)候動(dòng)態(tài)的修改它們的效果,這是個(gè)很強(qiáng)大的功能,比如動(dòng)態(tài)修改皮膚什么的,希望你們可以手動(dòng)去實(shí)現(xiàn)一下,?,謝謝。
總結(jié)
以上是生活随笔為你收集整理的从源码的角度说说Activity的setContentView的原理(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我在小程序工程化方面的一些实践
- 下一篇: 笔记:seafile 7.x 安装和部署