日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从源码的角度说说Activity的setContentView的原理(二)

發布時間:2024/7/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从源码的角度说说Activity的setContentView的原理(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前文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);}
通過查看源碼我們可以得知,在 PhoneWindow的構造方法里是LayoutInflater.from(context);的方式對mLayoutInflater對象進行了初始化,看來,它也是和我們一樣使用了同一個系統提供的LayoutInflater對象,那么,系統提供的這個LayoutInflater對象是在哪被構造和添加進去的呢?這我們就需要去Context.getSystemService方法里一探究竟了:

我們知道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);}
好,看來所有的服務都是通過SYSTEM_SERVICE_MAP取出來的,那么我們看看這些服務什么時候被添加進去的,在 ContextImpl這個類中我們看到有個靜態方法

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());}});...}
好吧,看來系統系統的 LayoutInflater的對象其實是由PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());這個方法構造出來的(又是PolicyManager,我們剛才看到它執行的makeNewWindow,看來它做了不少事情), 不用多說,我們直接進入Policy中看(不清楚這個過程的同學可以直接看這里 http://blog.csdn.net/sahadev_/article/details/49072045 ):

public LayoutInflater makeNewLayoutInflater(Context context) {return new PhoneLayoutInflater(context);}噢,原來所有的工作都是它在干啊!到這里,我們第一個問題就清楚了。


2.mLayoutInflater對象后來所調用的那些方法有沒有被重載?其實這個問題我們直接進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);}
噢,原來我們在上一篇文章當中分析的onCreateView方法是沒有被調用的,那看來父類中的這個方法的功能是不滿足的,那我們分析分析被復寫的這個方法:

我們可以看到這個方法內部在遍歷一個字符串數組,這個字符串數組被定義在類里:

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);}
后來也沒有對它進行什么設置,所以看來它們都是空,這里這3個對象是開放給我們使用的,我們可以在View被加載的時候動態的修改它們的效果,這是個很強大的功能,比如動態修改皮膚什么的,希望你們可以手動去實現一下,?,謝謝。


總結

以上是生活随笔為你收集整理的从源码的角度说说Activity的setContentView的原理(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。