activity和view之間的關係。Android Activity 、 Window 、 View之間的關係。
https://blog.csdn.net/haiyang497661292/article/details/78097775
一、簡述如何將Activity展現在手機上
Tips:
Activity本身是沒辦法處理顯示什麼控制元件(view)的,是通過PhoneWindow進行顯示的
換句話說:activity就是在造PhoneWindow,顯示的那些view都交給了PhoneWindow處理顯示
1、在Activity建立時呼叫attach方法:
2、attach方法中會呼叫PolicyManager.makeNewWindow()
實際工作的是IPolicy介面的makeNewWindow方法
①、其中建立了一個window(可以比喻為一個房子上造了一個窗戶):mWindow = PolicyManager.makeNewWindow(this);
②、在window這個類中,才呼叫了setContentView(),這是最終的呼叫
在Activity的setContentView方法中,實際上是呼叫:getWindow().setContentView(view, params);
這裡的getWindow()就是獲取到一個Window物件
Tips:
為啥attch優先於onCreate呼叫,就是由於在attch方法中,會建立window,有了window才能呼叫setContentView
3、在IPolicy的實現類中建立了PhoneWindow:
①、由mWindow = PolicyManager.makeNewWindow(this);,
②、這裡的makeNewWindow(this);方法中,返回的是:return sPolicy.makeNewWindow(context);
③、這個sPolicy實際是一個介面,其實現類是Policy,其中只是建立了一個PhoneWindow
4、在PhoneWindow的setContentView中向ViewGroup(root)中添加了需要顯示的內容
①、PhoneWindow是繼承Window的
②、setContentView這個方法中,需要先判斷一個mContentParent是否為空,因為在預設進來的時候,什麼都沒建立呢
此時需要建立:installDecor(),DecorView是最根上的顯示的
可以通過adt中的的tools中有個hierarchyviewer.bat的工具,可以檢視手機的結構
③、DecorView:是繼承與FrameLayout的,作為parent存在,最初顯示的
④、下次再載入的時候,mContentParent就不為空了,會將其中的所有的view移除掉,然後在通過佈局填充器載入佈局
二、三者關係:
1、在Activity中呼叫attach,建立了一個Window
2、建立的window是其子類PhoneWindow,在attach中建立PhoneWindow
3、在Activity中呼叫setContentView(R.layout.xxx)
4、其中實際上是呼叫的getWindow().setContentView()
5、呼叫PhoneWindow中的setContentView方法
6、建立ParentView:
作為ViewGroup的子類,實際是建立的DecorView(作為FramLayout的子類)
7、將指定的R.layout.xxx進行填充
通過佈局填充器進行填充【其中的parent指的就是DecorView】
8、呼叫到ViewGroup
9、呼叫ViewGroup的removeAllView(),先將所有的view移除掉
10、新增新的view:addView()
Tips:
①、Activity就是在造“窗戶”,即建立PhoneWindow
②、PhoneWindow才是進行顯示view的操作,主要就是setContentView()
setContentView整個過程主要是如何把Activity的佈局檔案或者java的View新增至窗口裡,重點概括為:
-
建立一個DecorView的物件mDecor,該mDecor物件將作為整個應用視窗的根檢視。
-
依據Feature等style theme建立不同的視窗修飾佈局檔案,並且通過findViewById獲取Activity佈局檔案該存放的地方(視窗修飾佈局檔案中id為content的FrameLayout)。
-
將Activity的佈局檔案新增至id為content的FrameLayout內。
-
當setContentView設定顯示OK以後會回撥Activity的onContentChanged方法。Activity的各種View的findViewById()方法等都可以放到該方法中,系統會幫忙回撥。
LayoutInflater的使用中重點關注inflate方法的引數含義:
-
inflate(xmlId, null); 只建立temp的View,然後直接返回temp。
-
inflate(xmlId, parent); 建立temp的View,然後執行root.addView(temp, params);最後返回root。
-
inflate(xmlId, parent, false); 建立temp的View,然後執行temp.setLayoutParams(params);然後再返回temp。
-
inflate(xmlId, parent, true); 建立temp的View,然後執行root.addView(temp, params);最後返回root。
-
inflate(xmlId, null, false); 只建立temp的View,然後直接返回temp。
-
inflate(xmlId, null, true); 只建立temp的View,然後直接返回temp。
1,如何理解Activity,View,Window三者之間的關係?
這個問題真的很不好回答。所以這裡先來個算是比較恰當的比喻來形容下它們的關係吧。Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示檢視)LayoutInflater像剪刀,Xml配置像窗花圖紙。
1:Activity構造的時候會初始化一個Window,準確的說是PhoneWindow。
2:這個PhoneWindow有一個“ViewRoot”,這個“ViewRoot”是一個View或者說ViewGroup,是最初始的根檢視。
3:“ViewRoot”通過addView方法來一個個的新增View。比如TextView,Button等
4:這些View的事件監聽,是由WindowManagerService來接受訊息,並且回撥Activity函式。比如onClickListener,onKeyDown等。