1. 說明
今天我們來看下Window底層原理太抓,這個就要求我們必須對下邊的知識要非常之清楚:
當app一運行到手機上邊時乙埃,我們一定要清楚的知道:
一定要在心里面對FrameWork層的源碼有一個架構(gòu)吱窝、Activity是怎么啟動的、布局文件是怎樣加載的夷野、資源怎么加載的、View的繪制流程荣倾、View的Touch事件悯搔、IPC進程間通信機制、Handler源碼分析
2. 分析
我們一開始開發(fā)時可能聽的最多的就是四大組件舌仍,那么到后期可能就會聽到AMS以及其他的一些名詞妒貌,那么我們就來看下這些都代表什么意思?
AMS:指的是 ActivityManagerService 有Activity、ActivityManager铸豁;
WMS(窗口有關(guān)):Window灌曙、WindowManager、WindowManagerService节芥、Token在刺、Session、ViewRootImpl头镊、View(我們就只是講了DecorView)
當面試如果問你AMS和WMS是怎樣建立聯(lián)系的蚣驼,也就是說Activity、View相艇、Window之間的聯(lián)系是怎樣的颖杏?
回答:
其實ActivityManagerService和WindowManagerService的設(shè)計模式以及它們的設(shè)計風(fēng)格其實是差不太多的,都是跨進程之間的通訊的坛芽,AMS有Activity留储、ActivityManager、ActivityManagerService咙轩,而WMS中有Window获讳、WindowManager、WindowManagerService活喊,只不過WMS中有Token赔嚎、Session、ViewRootImpl(DecorView是根布局)
Activity中有PhoneWindow胧弛,PhoneWindow中有一個根布局DecorView,會首先給WindowManager侠畔,然后WindowManager其實什么都沒做结缚,它是交給WindowManagerGlobal這個單例來統(tǒng)一去管理,因為只有單例才適合去做我們的管理類软棺,原因就是 單例是一直存在于我們的內(nèi)存中红竭,不會隨著Activity的退出而銷毀。而DecorView傳遞到WindowManagerGlobal之后,它會去創(chuàng)建ViewRootImpl ,即就是ViewRoot的實現(xiàn)類茵宪,ViewRootImpl這個實現(xiàn)類有2個作用:
第一個就是和遠程的WindowManagerService進行通信的最冰,會首先從遠程的服務(wù)端中去獲取session來通信,因為我們應(yīng)用無法操作系統(tǒng)的布局稀火,比如說點擊輸入法暖哨,就需要通知系統(tǒng)讓輸入法彈起來,所以只能通過這樣的方式來進行通信凰狞;
第二個就是與View的繪制流程 篇裁;
那么我們接下來就來看下app剛運行到手機上邊時,我們都做了哪些工作赡若?
2.1 當手機剛一運行app時候調(diào)用setContentView() ->
2.2 Activity里邊有PhoneWindow 达布,調(diào)用PhoneWindow設(shè)置setContentView()布局 ,而setContentView()方法中就是去創(chuàng)建一個根View逾冬,即就是DecorView 黍聂,然后加載系統(tǒng)默認的布局,然后解析我們設(shè)置的資源布局添加到android.R.id.content中身腻,也就是添加到ContentParent中产还。PhoneWindow的setContentView()這個方法執(zhí)行完畢后只是去解析加載我們的布局,即就是activity_main.xml文件霸株,然后什么都沒干->
那么我們自己的activity_main.xml的布局文件是怎樣顯示出來的呢雕沉??去件?
3. 布局的顯示繪制流程
Activity中的源碼坡椒,里邊有一個PhoneWindow:
final void attach(Context context, ActivityThread aThread,
mWindow = new PhoneWindow(this, window);
PhoneWindow中的源碼,里邊有一個setContentView()方法:
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
3.1 activity_main.xml布局文件是怎樣顯示出來的尤溜?
Activity中的attach()方法倔叼,會綁定設(shè)置Activity的一些參數(shù),Activity里邊有一個PhoneWindow宫莱,即就是new PhoneWindow() 丈攒,Window里面有一個WindowManager
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
Activity是通過反射創(chuàng)建出來的,在ActivityThread中的performLaunchActivity()方法中
WindowManager.LayoutParams 和RelativeLayout.LayoutParams差不多授霸,而RelativeLayout.LayoutParams是用來描述布局的一些信息的巡验,意思就是:
比如在activity_main.xml布局文件中有一個TextView,如果你的根布局是RelativeLayout碘耳,并且給TextView設(shè)置了
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
那么對于TextView是有作用的显设;
如果你的根布局是LinearLayout的話,那么設(shè)置這兩個屬性就沒有作用辛辨,因為LinearLayout源碼中就沒有定義這兩個屬性捕捂,就像RelativeLayout源碼中沒有定義
android:layout_gravity="center"
android:gravity="center"
這兩個屬性一樣瑟枫。
3.2 wm.addView(decor , 1);
這個方法在布局的繪制流程中看過指攒,WindowManager的實現(xiàn)類是WindowManagerImpl慷妙,實際上調(diào)用的是WindowManagerGlobal,而WindowManagerGlobal是一個單例允悦,單例設(shè)計模式意思就是一直在我們的內(nèi)存中膝擂,不會隨著Activity的退出而銷毀,而我們項目中肯定有很多的Activity澡屡,也會對應(yīng)的有很多的布局文件猿挚,所以它就會去管理Activity,而且像一些管理類都是單例
findViewLocked(view 驶鹉, false)绩蜻;意思就是如圖所示:
Activity1、Activity2都會去調(diào)用setContentView()方法室埋,而且他們都會有一個DecorView办绝,而這兩個Activity都是由 WindowManagerGlobal這個單例來管理
ViewRootImpl
總結(jié)布局文件繪制流程順序如下
activity ->
PhoneWindow(DecorView) ->
WindowManager(不是單例,所以有多個) ->
WindowManagerGlobal(是單例姚淆,只有1個) ->
ViewRootImpl(有多個孕蝉,但是一個ViewRootImpl只會綁定一個DecorView)
也就是說:
activity里邊有一個PhoneWindow ->
PhoneWindow里邊有一個DecorView ,DecorView最終是交給一個全局變量去管理的腌逢,而這個全局變量中就存儲了很多的變量降淮,有ViewRootImpl ->
而ViewRootImpl是用來和遠程服務(wù)去通信的 ->
頁面是交給WindowManagerGlobal這個單例類去管理的
跨進程通信就意味著:app應(yīng)用和系統(tǒng)服務(wù)一定要建立連接
4. requestLayout()方法 —— 百度、阿里搏讶、騰訊等等大公司都會必問的一個問題
是View繪制流程的入口佳鳖,在這個方法中做了3件事
performMeasure()、performLayout()媒惕、performDraw()系吩,測量、擺放妒蔚、繪制
這個很重要穿挨,百度、阿里肴盏、騰訊等等大公司都會必問的一個問題科盛,就是View的繪制流程