Activity、View、Window的理解一篇文章就夠了
要了解這三者之間的關係,我們帶著問題通過分析原始碼一步一步來揭開它們的神祕面紗!
文章有點長,首先要理解Activity、View、Window,我提出了一些問題,這篇文章可以解答如下問題:
1、為什麼要設計Activity、View、Window?
2、Activity工作過程是什麼樣的?(理解Activity)
3、Window是什麼?它的職能是什麼?
4、View跟Window有什麼聯絡?
5、Activity、View、Window三者如何關聯?
1、為什麼要設計Activity、View、Window?
用一句話來聯絡他們之間的關係:
Activity就像工匠,Window就像是窗戶,View就像是窗花,LayoutInflater像剪刀,Xml配置像窗花圖紙。
Android根據他們不同的職能讓他們各斯其活,同時也相互配合展示給我們靈活、精緻的介面。
一張圖理清所有層級關係:
好了,接下來一步一步的分析,首先從大家最熟悉的Activity開始:
我們的工匠大神Activity
Activity工作過程:
啟動:
從startActivity開始,它會呼叫到Instrumentation,然後Instrumentation通過Binder向AMS(ActivityManagerService)發請求,通過PIC啟動Activity。而這個AIDL操作的方法定義在ApplicationThread中(裡面包括了Activity所有的生命週期方法的呼叫)。然後通過Handle回到主執行緒啟動activity。
因為中間流程太多,詳細寫出來容易造成“見其樹木,而不見其森林”的局面。
啟動Activity所執行的操作:
1、從ActivityClientRecord中獲取待啟動的Activity元件資訊
2、通過Instrumentation的newActivity方法使用類載入器建立Activity物件
3、通過LoadedApk的mackApplication方法來嘗試建立Application物件(如果Application已經建立,則不會重複建立)
4、建立ContextImpl物件,並通過Activity的attach方法來完成一些重要資料的初始化(包括讓Activity跟Window關聯)
5、呼叫Activity的onCreate方法
美麗的窗花View
View如何跟Activity關聯起來的?
其實View並不是直接跟Activity關聯起來的,而是通過Window這個中間人。如前面所說,View只是窗花,Window才是直接關聯到Activity上的。那麼:
View如何跟Window關聯起來呢?
下面先了解一下Window,就可以理解這個問題了
靈活的窗戶Window
Window如何跟Activity關聯?
每一個Activity都包含了唯一一個PhoneWindow,這個就是Activity根Window(之所以是說根Window是因為在它上面可以增加更多其他的Window,例如:彈出框(dialog))
那麼,PhoneWindow如何跟Activity關聯起來的呢?
來個最簡單的,setContentView其實就讓View與Window關聯,Window跟Activity關聯起來了。
那setContentView不是View跟Activity關聯嗎?
真相見Activity原始碼:
明顯是將layout設定到Window上了,那這個 getWindow() 返回的Window是誰呢? 是不是前面提及PhoneWindow?
真的是PhoneWindow,在 attach 的時候執行了PhoneWindow的初始化。
提到了 activity 的 attach 方法,該方法是在執行Activity啟動時在ActivityThread裡面的performLaunchActivity呼叫的。performLaunchActivity裡面做了很多Activity啟動過程具體的操作,例如:主題、記錄Activity棧、執行Activity onCreate 方法等。
這麼說來setContentView其實就是將View設定到Window上,Activity展示的其實是PhoneWindow上的內容。那麼其實 setContentView 實際上是呼叫的 getWindow().setContentView。
PhoneWindow是個什麼東西?它作為Activity跟View的中間人,它做了哪些工作?
首先 PhoneWindow 本身就是一個 Window。
從setContentView來分析:
這裡的 mContentParent 其實是一個 ViewGroup。這麼看來就簡單了。PhoneWindow裡面包含了一個ViewGroup,setContentView其實就是將layout設定到了這個ViewGroup上了。
我們再看看這張圖:
DecorView是啥?
它直接跟PhoneWindow關聯起來的,有了mContentParent,為啥還需要DecorView?
如圖所見,DecorView它不僅包含了我們自己的佈局,它還包含了titleBar。為啥需要?結構上的需要,更好的管理佈局。
Window作為中間人,已經關聯了Activity跟View了,那麼如果處理Activity跟View之間的關係呢?
是時候揭開Window這個神祕面紗了:
之前提的PhoneWindow是繼承於Window的,它是連線Activity跟View之間的橋樑。所有對View的一些操作都需要藉助這個橋樑。
為了更好的理解Window,我們先從Dialog入手。在Activity中展示一個對話方塊的流程是怎樣的?
為啥從Dialog入手,因為它裡面包含了Window,而且可以直接操作Window裡面的View,這樣就能瞭解Window是如何控制View的,以及自定義Window怎麼展示到Activity上(因為了解Dialog,就知道怎麼讓自定義的Window與Activity關聯了)
我們省去所有的Dialog build的方法。直接從AlertDialog.show()方法開始:
可見show()方法裡面執行了create()方法,繼續看create()方法做了什麼事:
new 了一個 AlertDialog,那麼跟蹤它的構造方法看看:
AlertDialog構造方法裡面最後執行的是這個構造方法,這裡找到了亮點:
1、mWindow是啥?是不是PhoneWindow?
首先AlertDialog是繼承Dialog的,mWindow就是Dialog裡面初始化的物件,看看是不是PhoneWindow,如果是,那麼就可以猜到通過在PhoneWindow新增View就可以在Activity上展示了,因為經過上面分析Activity是跟PhoneWindow有關聯的。帶著問題繼續分析原始碼:
果然如此,太開心了。
2、AlertController是啥?
從這兩個屬性就知道了,設定Title、Message的。用過Dialog的人都知道他們是啥,就不多說了。
既然這樣關聯起來了,那麼Window怎麼對View操控的呢?
WindowManager是主角。
在Dialog build之後就將View設定進來了,繼續追蹤Dialog show()這個方法,這個方法會將View與Window相互聯絡:
因為電腦螢幕大小受限,就截了兩個圖。
mWindowManager.addView,看到這個方法,可以猜想到WindowManager是個啥玩意了。
從原始碼註釋可看出,WindowManager是對Window進行操作的。它可以做哪些操作?
好了,真相揭曉了。Window對View的操作是通過WindowManager來處理的。WindowManager提供在Window上新增View、移除View、更新View的操作。
然而可見 WindowManager 其實只是一個介面,真正的實現類是WindowManagerImpl
以addView為例,裡面有點繞,直接忽略中間過程,最後執行addView的是通過ViewRootImpl完成Window的新增工作的,它執行了View的requestLayout方法,在requestLayout方法裡會通過WindowSession完成Window的新增過程WindowSession是IWindowSession型別的,它是一個Binder物件,因此Window的新增工作其實是一次IPC呼叫。好了,大致流程就是如此,這樣就更新介面了。
總結:
1、為什麼要設計Activity、View、Window?
Activity就像工匠,Window就像是窗戶,View就像是窗花,LayoutInflater像剪刀,Xml配置像窗花圖紙。
Android根據他們不同的職能讓他們各斯其活,同時也相互配合展示給我們靈活、精緻的介面。為啥這樣設計?因為這樣的結構更好管理。就像為啥需要使用MVP、MVVM、各種設計模式一樣。
2、Activity工作過程是什麼樣的?
以Activity啟動過程為例,Activity啟動時是通過Binder向AMS(ActivityManagerService)發請求,通過PIC啟動Activity的。
3、Window是什麼?它的職能是什麼?
Activity要管理View需要通過Window來間接管理的。Window通過addView()、removeView()、updateViewLayout()這三個方法來管理View的。
4、View跟Window有什麼聯絡?
View需要通過Window來展示在Activity上。
5、Activity、View、Window三者如何關聯?
Activity包含了一個PhoneWindow,而PhoneWindow就是繼承於Window的,Activity通過setContentView將View設定到了PhoneWindow上。Window的新增過程以及Activity的啟動流程都是一次IPC的過程。Activity的啟動需要通過AMS完成;Window的新增過程需要通過WindowSession完成。
你竟然看完了,非常感謝你的支援,希望這篇文章對你有幫助~