android中創建應用窗口

如前面的那篇帖子所述,每個應用窗口對應一個Activity,所以要創建應用窗口的話,首先要創建Activity。
在Context與Activity的關系那篇帖子中也講解瞭Activity的創建過程,我下面就直接上源碼,直接加一些
必要的註釋,如果不明白的,可以自行查看源碼,就不對每一句代碼一一解釋瞭。

ps:技術能力有限,難免會有錯誤,敬請各位指正,感謝…

大體步驟入下:

    創建Activity創建Window向窗口中添加View通知WindowManagerService把窗口裝載到屏幕上

    創建Activity

    ActivityManagerService通過ApplicationThread的代理遠程調用到瞭ApplicationThread的scheduleLaunchActivity()方法,
    ApplicationThread這個類是ActivityThread的內部類。
    代碼入下:

    這個方法做瞭兩件事:一件事創建瞭一個本地的Activity的數據對象ActivityClientRecZ喎?/kf/ware/vc/” target=”_blank” class=”keylink”>vcmRlcqO70ru8/srCysfNqLn9SLeiy83Su7j2xvS2r0FjdGl2aXR5tcTS7LK9z/vPorW91vfP37PMtcTP+8+ittPB0NbQyKWhozwvc3Ryb25nPgo8c3Ryb25nPtTa1eLA79ei0uLSu8/Cci50b2tlbqOs1eK49nRva2Vuyse49kJpbmRlcrbUz/OjqEFjdGl0aXR5UmVjb3JkZXKjqaOsysdBY3Rpdml0eU1hbmFnZXJTZXJ2aWNl1LazzLSrtd25/cC0tcSjrMq508PV4rj2dG9rZW6/ydLU0+vUtrPMtcRBY3Rpdml0eU1hbmFnZXJTZXJ2aWNlvfjQ0L34s8y85M2o0MWhozwvc3Ryb25nPgo8YnI+Cgo8c3Ryb25nPs2ouf1Io6hIYW5kbGVyo6nVt9eqtffTw7X0wctBY3Rpdml0eVRocmVhZLXE1eK49re9t6ijumhhbmRsZUxhdW5jaEFjdGl2aXR5KCk8L3N0cm9uZz4KPGJyPgoKPGltZyBzcmM9″https://www.aiwalls.com/uploadfile/Collfiles/20131202/clipboard.png” height=”120″ width=”846″ alt=”\”>
    接著調用到performLaunchActivity()方法


    …….
    …….

    通過ClassLoader創建瞭一個Activity實例
    繼續這個方法:

    看下Activity的attach()方法


    部分參數解釋一下,token就是ActivityServiceManager傳遞過來的遠程的ActivityRecorder,parent是需要啟動的Activity的父Activity,這個是ActivityGroup裡啟動Activity的時候,這個就不為null瞭,其他情況下是null。


    開始創建window瞭


    下面是這個attach()方法的具體代碼

    從這裡就開始創建Window的實例瞭:3756行

    mWindow = PolicyManager.makeNewWindow(this);
    mWindow.setCallback(this);

    第一句是創建一個window對象,第二句是為Activity設置一個回調接口,Activity實現瞭Window.Callback接口


    看下這個PolicyManager,
    這個PolicyManager是這個包裡的com.android.internal.policy,看這個PolicyManager源碼可知道,真正的操作類
    並不是他,而是com.android.internal.policy.impl.Policy這個,實現的是com.android.internal.policy.IPolicy這個接口,
    Activity中的PolicyManager隻是包裝瞭一層com.android.internal.policy.impl.Policy而已。
    下面是創建Ipolicy實例的源碼,直接在加載字節碼的時候已經就實例化瞭。



    com.android.internal.policy.IPolicy總共三個方法:

    看下PolicyManager.makeNewWindow(this);這個方法:

    調用瞭com.android.internal.policy.impl.Policy的makeNewWindow()


    順著走下去

    這裡直接new瞭一個PhoneWindow給返回瞭。參數中的context就是傳過來的Activity
    PhoneWindow的構造方法裡面把context賦值給瞭它的mContext,創建瞭一個當前Activity的LayoutInflater
    代碼入下:

    調用瞭下父類的構造器:

    所以應用窗口的Window.getContext()就是返回的Activity的實例

    到這裡Window已經建立起來瞭,咱們再回到Activity的attach()方法:
    mWindow就是PhoneWindow的實例。

    3777行是為Window對象賦值WindowManager
    進去看下:

    window的appToken就是Activity中的mToken.
    調用這個方法的時候wm傳的是null,所以第一次調用的時候肯定會創建一個WindowManagerImpl的實例,是單例的,同一個
    程序隻有一個WindowManagerImpl實例。然後把wm包裝到LocalWindowManager中,可以看出 LocalWindowManager
    隻是一個殼。然後把這個殼返回給Activity。
    再次回到Activity的attach()方法:
    3781行把這個WindowManager實例賦值給瞭Activity的mWindowManager。


    再次回到ActivityThread的performLaunchActivity()方法中

    1611行調用瞭Activity的onCreate()方法
    Instrumentation中的代碼如下:

    1047行調用瞭activity的onCreate()方法
    在Activity的onCreate方法中的重載就是咱們應用程序員的事情瞭,咱們通常要在conCreate()方法調用setContentView()來
    把佈局文件或者View對象設置進去,之後界面就出現瞭。


    開始添加View瞭


    下面看看這個過程:
    在Activity的onCreate()方法

    mCalled表示代表onCreate方法是否被調用過。


    我們自己的Activity的代碼通常這麼寫:

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate();
    setContentView(R.layout.main);

    }

    這個方法我們重寫的父類的,應用程序寫的代碼不是由自己調用而是由Android系統調用,那麼這種就是所謂的回調模式,通常
    平臺級的產品都是這麼設計,這樣設計就是給開發者一個標準的模板,相當於協議,做平臺的一個程序,就一般按照平臺
    的這種模式去寫,好處就是:對於平臺來說,可控。對於開發者來說,簡單。

    應用開發者又調用瞭Activity的
    setContentView()方法,有幾個重載的方法,隻看一個,咱們進去看看這個方法怎麼執行的:


    getWindow就是咱們上面創建的PhoneWindow對象。
    進入 PhoneWindow 的setContentView()方法

    mContentParent是一個ViewGroup,如果為空的話,會執行
    installDecor();
    看下這個方法:

    第一次加載的時候mDecor是null,generateDecor()方法就會創建一個DecorView對象賦值給mDecor,通過new DecorView(getContext(), -1);
    DecorView是個ViewGroup,是FramLayout的子類,這個DecorView就是我們看到的包括標題欄在內的整個窗口的根View


    generateLayout(mDecor)方法找出mContentParent
    這個地方還對標題欄的顯示與否做瞭一些操作,所以在我們不需要系統提供的標題欄的時候為什麼要在setContentView()之前就
    告訴系統去掉標題欄,在setContentView()之後告訴系統去掉報錯的原因。
    回到 PhoneWindow 的setContentView()方法
    207行,mLayoutInflater.inflate(layoutResID, mContentParent)這個方法就把應用開發者傳過來的佈局文件給裝載到
    mContentParent上瞭。
    mContentParent是mDecor的一個子視圖,在標題欄下面,mContentParent就是用來存放我們應用開發者的view的。
    下面請看下view層次結構:

    208行到結束,回調Activity的onContentChanged()方法,告訴activity視圖內容改變瞭。

    到這裡,回到ActivityThread的performLaunchActivity()



    在這裡可以看出不調用Activity的concreate方法,系統是不允許的。

    mActivities就是放Activity數據對象的集合,用來代表所有的Activity

    再次回到ActivityThread的handleLaunchActivity()方法:


    handlerResumeActivity()就是到執行到Actitiviy onResume()方法之前的一系列判斷,及從onCreate()到onResume()之間的聲明周期函數。


    開始添加讓窗口顯示瞭




    接著看這個


    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
    a.getActivityToken());

    遠程調用ActivityManagerService的willActivityBeVisible()方法,把Activity裡面的mToken傳遞過去,mToken其實是一個遠程ActivityRecorder的Binder引用,這個ActivityRecorder代表服務端的Activity對象。ActivityRecorder實現瞭IBinder。
    上面的方法主要是檢查遠端是否存在這個即將啟動Activity。

    繼續走下去

    上面的willBeVisible 是true,
    就執行到這裡瞭
    調用瞭Activity的makeVisible()方法

    然後又調用瞭WindowManager的addView()方法,
    調用的是Window.LocalWindowManager的addView()方法,先做一些檢查,像下面的代碼就是檢查是否為子窗口,然後做一些數據
    的處理。
    ‘’
    接著就調用瞭WindowManagerImpl的addView()方法


    重載的addView方法如下

    先創建一個ViewRoot對象,
    創建三個數組

    mViews存放的是DecorView
    mRoots就是和DecorView對應的ViewRoot
    mParams就是對應的WindowManager.LayoutParams
    每個index都對應同一個窗口。

    然後調用ViewRoot的setView方法

    先發出重繪請求,在繪制完之後才把窗口顯示在屏幕上。

    然後通過sWindowSession通知WindowManagerService可以把窗口添加到屏幕上瞭
    這樣應用的窗口就被創建成功瞭。其實最重要的一操作就是上面這段代碼,前面的都是為這裡做瞭一個準備而已。

    解釋一下sWindowSesion對象

    這個對象是ViewRoot一個靜態方法獲得的,也就是說整個應用程序隻有一個IWindowSession對象


    通過ServiceManager獲得IWindowMananger的Binder引用,然後獲得遠程可以和WindowManagerService進行通信的對象
    Session對象的遠程引用對象.
    在WindowManagerService類裡面有Session mSession對象,就是應用的這個對象,可以通過mSession與WindowManagerService進行通信。




    下面是各個類之間的關系,ActivityThread沒有放進去,大傢知道就可以瞭。






發佈留言