第8章 理解Window和WindowManager

第8章 理解Window和WindowManager

Window表示一個窗口的概念。Window是一個抽象類,它的具體實現是PhoneWindow。WindowManager是外界訪問Window的入口,Window的具體實現位於WindowManagerService中,WindowManager和WindowManagerService的交互是一個IPC過程。Android中所有的視圖都是通過Window來呈現的,他們的視圖實際上都是附加在Window上的,因此,Window實際是View的直接管理者。

8.1 Window和WindowManager

通過WindowManager添加Window的過程:

WindowManager windowManager=(WindowManager) getSystemService(Context.WINDOW_SERVICE);
Button button=new Button(this);
button.setText("this is a button");
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        System.out.println("click");
        Intent intent=new Intent(v.getContext(), RemoteActivity.class);
        startActivity(intent);
    }
});
WindowManager.LayoutParams layoutParams=new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,0,0, PixelFormat.TRANSPARENT);
layoutParams.flags= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
layoutParams.gravity= Gravity.LEFT|Gravity.TOP;
layoutParams.x=100;
layoutParams.y=300;
windowManager.addView(button,layoutParams);

Flags參數表示Window的屬性有幾個常用的選項:

  • FLAG_NOT_FOCUSABLE:表示Window不需要獲取焦點,也不需要接收各種輸入事件,此標記會同時啓用FLAG_NOT_TOUCH_MODAL,最終事件會直接傳遞個下層的具有焦點的Window。
  • FLAG_NOT_TOUCH_MODAL:在此模式下,系統會將當前Window區域以外的單擊事件傳遞給底層的Window,當前Window區域以內的單擊事件則自己處理。
  • FLAG_SHOW_WHEN_LOCKED:開啓此模式可以讓Window顯示在鎖屏的界面上。

Type參數表示Window的類型,Window有三種類型,分別是應用Window,子Window和系統Window。應用類Window對應着一個Activity。子Window不能單獨存在,它需要附屬在特定的父Window之中,比如Dialog。系統Window是需要聲明權限才能創建的Window,比如Toast和系統狀態欄。

Window是分層的,每個Window都有對應的z-ordered,層級大的會覆蓋在層級小的Window上面。應用Window的層級範圍是1~99,子Window的層級範圍是1000~1999,系統Window的層級範圍是2000~2999。這些層級範圍對應着WindowManager.LayoutParams的type參數。

8.2 Window的內部機制

8.2.1 Window的添加過程

Window的添加過程需要通過WindowManager的addView來實現。

  • 檢查參數是否合法,如果是子Window那麼還需要調整一些佈局參數
  • 創建ViewRootImp並將View添加到列表中
  • 通過ViewRootImpl來更新界面並完成Window的添加過程:這個過程由ViewRootImp的setView方法來完成,在setView內部會通過requestLayout來完成異步刷新請求,接着通過WindowSession最終來完成Window的添加過程。

8.2.2 Window的刪除過程

WindowManager中提供了兩種刪除接口removeView和removeViewImmediate,他們分別表示異步刪除和同步刪除,其中remvoeViewImmediate使用起來需要特別注意,一般來說不需要使用此方法來刪除Window以免發生意外錯誤。

  • removeView()
  • removeViewLocked()
  • die()
  • 同步刪除doDie(),異步刪除發送MSG_DIE消息
  • doDie()內部調用dispatchDetachedFromWindow方法
  • dispatchDetachedFromWindow方法內部調用WindowSession.remove(mWindow);

8.2.3 Window的更新過程

  • 調用WindowManager的updateViewLayout方法
  • 調用WindowManagerGlobal的updateViewLayout方法
  • 調用root.setLayoutParams()方法
  • 調用scheduleTraversals()方法,開始重新測量,佈局,繪製

8.3 Window的創建過程

8.3.1 Activity的Window創建過程

Window創建流程:

PhoneWindow的setContentView方法步驟:

  1. 如果沒有DecorView,那麼就創建它

DercorView是一個FrameLayout,DecorView是Activity中的頂級View,一般來說它的內部包含標題欄和內部蘭,但是這個會隨着主題的變換而發生改變。內容欄是一定要存在的,並且內容欄具有固定的id,就是“content”,它的完整id是android.R.id.content。

  1. 將View添加到DecorView的mContentParent中

  2. 回調Activity的onContentChanged方法通知Activity視圖已經發生改變

Activity的佈局文件已經成功添加熬了DercorView的mContentParent中,但是這個時候DecorView還沒有被WindowManager正式添加到Window中。在ActivityThread的handleResumeActivity方法中,首先會調用Activity的onResume方法,接着會調用Activity的makeVisible()。

大致流程:

###8.3.2 Dialog的Window創建過程

Dialog的Window的創建過程和Activity類似。

  • 創建Window
  • 初始化DercorView並將Dialog的視圖添加到DercorView中
  • 將DecorView添加到Window中並顯示

普通的Dialog有一個特殊之處,那就是必須採用Activity的Context,如果採用Application的Context,那麼就會報錯。

系統Window比較特殊,它可以不需要token,但是使用時需要在AndroidManifest文件中聲明權限。

8.3.3 Toast的Window創建過程

在Tost的內部有兩類IPC過程,第一類是Toast訪問NotificationManagerService,第二類是NotificationManagerService回調Toast裏的TN接口。

當NotificationManagerService處理Toast的顯示或隱藏請求時會跨進程回調TN中的方法,這個時候由於TN運行在Binder線程池中,所以需要通過Handler將其切換到當前線程中。這裏的線程是指發送Toast請求所在的線程。

流程:

發佈了32 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章