Window和WindowManager

參考資料

凱子哥帶你學(xué)Framework· Activity界面顯示全解析-上
凱子哥帶你學(xué)Framework Activity界面顯示全解析-下
重要:?。?! Android 屏幕刷新機制


目錄

  • 1)簡介
  • 2)Window的內(nèi)部機制
    • 2.1)Window的添加過程
    • 2.2)Window的刪除過程
    • 2.3)Window的更新過程
  • 3)Window的創(chuàng)建過程
    • 3.1)Activity的Window創(chuàng)建過程
    • 3.2)Dialog的Window創(chuàng)建過程
    • 3.3)Toast的Window創(chuàng)建過程

1)簡介

  • Window是一個抽象類,具體實現(xiàn)為PhoneWindow
  • 只需要WindowManager即可創(chuàng)建一個Window
  • WindowManager是個接口,是外界訪問Window的入口,具體實現(xiàn)位于WindowManagerService(WMS),WindowManager和WindowManagerService的交互是一個IPC過程
  • Android所有視圖都是附加在Window上,通過Window來呈現(xiàn),因此Window是View的直接管理者。如事件分發(fā)就是通過Window傳遞給DecorView。
  • 站在系統(tǒng)角度,Window代表一塊顯示區(qū)域,系統(tǒng)并不關(guān)心Window內(nèi)的繪制內(nèi)容
//WindowManager可以通過下面兩種方式進行獲取
WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 
WindowManager mWindowManager = (WindowManager) getWindowManger();
//WindowManager添加一個Window
mWindowManager.addView(mButton, mLayoutParams); 

2)Window的內(nèi)部機制

Window是以View的形式存在,View的繪制流程從ViewRoot開始,ViewRoot對應(yīng)ViewRootImpl類,它是連接WindowManager和DecorView的紐帶。

public interface ViewManager  
{  
    public void addView(View view, ViewGroup.LayoutParams params);  
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);  
    public void removeView(View view);  
}  

->ViewManager.addView
->WindowManager.addView(也是接口,繼承ViewManager)
->WindowManagerImpl.addView(實現(xiàn)了WindowManager接口)
->WindowManagerGlobal.addView(接受WindowManagerImpl的委托,并構(gòu)建ViewRootImpl)
->ViewRootImpl.setView(ViewRooImpl是WindowManagerGlobal的addView方法中新建的對象)
->requestLayout(setView中的一個方法調(diào)用,調(diào)用performTraversals繪制整個view樹)
->WindowSession.addToDisplay(在setView方法中,它是一個Binder對象,用于與WindowManagerService進行IPC通信)
->Session(WindowSession的具體實現(xiàn))
->WindowManagerService(實現(xiàn)Window的添加)

ViewRootImpl負責(zé)管理視圖樹和與WMS交互,它是WindowManager和DecorView的紐帶,與WMS交互是通過WindowSession。而且ViewRootImpl也負責(zé)UI界面的布局與渲染,負責(zé)把一些事件分發(fā)至Activity,以便Activity可以截獲事件。大多數(shù)情況下,它管理Activity頂層視圖DecorView,它相當(dāng)于MVC模型中的Controller。


3)Window的創(chuàng)建過程

3.1)Activity的Window創(chuàng)建過程

Activity 四大組件之一, 是存放View對象的容器,也是我們界面的載體,可以用來展示一個界面。它有一個SetContentView()方法 ,可以將我們定義的布局設(shè)置到界面上
View 就是一個個視圖的對象
Window 抽象類,是一個頂層的窗口,它的唯一實例是PhoneWindow它提供標準的用戶界面策略,如背景、標題、區(qū)域,默認按鍵處理等

Activity就像是一扇貼著窗花的窗口,Window就想上窗口上面的玻璃,而View對象就像一個個貼在玻璃上的窗花。

  • Activity最終會由ActivityThread中的performLaunchActivity來完成啟動,此方法內(nèi)會通過類加載器創(chuàng)建Activity的實例對象,并調(diào)用attach關(guān)聯(lián)所依賴的上下文。
  • 在attach方法中,系統(tǒng)會創(chuàng)建Activity所屬的Window對象,并獲取了WindowManager對象。
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);/設(shè)置回調(diào)函數(shù),使得Activity可以處理一些事件,如dispatchTouchEvent()
  • setContentView()調(diào)用了Window的setContentView(),將界面繪制交給了Window對象,也就是View通過Activity添加到了Window上面。
    • DecorView是PhoneWindow的內(nèi)部類,繼承自FrameLayout,是最底層的界面
    • 如果沒有DecorView,則創(chuàng)建它
    • 將View添加到DecorView的mContentParent對象中
    • 回調(diào)Activity的onContentChanged()通知Activity視圖已改變
  • 經(jīng)過上面步驟DecorView已初始化,且Activity的布局也被添加到了DecorView的mContentParent對象中。但這時DecorView還沒有被WindowManager添加到Window中,
void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

在Activity的onResume()中,WindowManager會執(zhí)行addView(mDecorView,getWindow().getAttributes())。至此Activity的視圖才能被用戶看見。

20151028131646957.png

3.2)Dialog的Window創(chuàng)建過程

AlertDialog和Activity一樣,內(nèi)部有一個Window,我們構(gòu)造AlertDialog.Builder,通過Builder設(shè)置Dialog各種屬性,,這些參數(shù)會被放在一個名為P(AlertController類型)的變量中,在調(diào)用AlertDialog.Builder.create方法的時候,內(nèi)部首先會new一個 AlertDialog,AlertDialog的父類Dialog的構(gòu)造函數(shù)中會new一個PhoneWindow賦值給AlertDialog中的Window,并且為它設(shè)置了回調(diào)。AlertDialog創(chuàng)建之后執(zhí)行apply方法,將P中的參數(shù)設(shè)置賦值給Dialog,后我們調(diào)用Dialog.show方法展示窗口,內(nèi)部調(diào)用dispatchOnCreate,最終會走到setContentView,到此Dialog的Window和Dialog視圖關(guān)聯(lián)到了一起,最后執(zhí)行mWindowManager.addView方法,通過WindowManager將DecorView添加到Window之中,此時Dialog顯示在了我們面前。

  • 在Activity中使用Dialog的時候,為什么有時候會報錯“Unable to add window -- token is not valid; is your activity running?”?
    答:
    一般發(fā)生在Activity進入后臺,Dialog沒有主動Dismiss掉,然后從后臺再次進入App的時候。
    Window分為三種,子窗口,應(yīng)用窗口和系統(tǒng)窗口,子窗口必須依附于一個上下文,就是Activity,因為它需要Activity的appToken,
    子窗口的window,比如Dialog,想要顯示必須保證appToken與Activity保持一致,當(dāng)Activity銷毀,再次回來的時候,Dialog試圖重新創(chuàng)建,調(diào)用ViewRootImpl的setView()的時候會出問題,所以當(dāng)Activity不可見的時候,主動Dismiss掉Dialog,否則會因為appToken為空crash。
  • 在子線程中為什么不能顯示Toast?
    Toast源碼是與NotificationManagerService進行IPC通信,
    show()的時候,通過handler來接收,子線程中沒有handler,所以無法顯示??梢越o子線程添加Looper
sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
  • 為什么不能在setContentView()之后設(shè)置某些Window屬性標志?
public void setContentView(View view) {
        getWindow().setContentView(view);
        initWindowDecorActionBar();//初始化window屬性
}

在Activity.setContentView()之后,Window的一些特征位將被鎖定

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容