第8章 理解Window和WindowManager

(1)Window是抽象類,具體實現(xiàn)是PhoneWindow,通過WindowManager就可以創(chuàng)建Window。WindowManager是外界訪問Window的入口,但是Window的具體實現(xiàn)是在WindowManagerService中,WindowManager和WindowManagerService的交互是一個IPC過程。所有的視圖例如Activity、Dialog、Toast都是附加在Window上的。

(2)通過WindowManager添加View的過程:將一個Button添加到屏幕坐標為(100,300)的位置上

mFloatingButton = new Button(this);
mFloatingButton.setText("test button");
mLayoutParams = new WindowManager.LayoutParams(
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
        PixelFormat.TRANSPARENT);//0,0 分別是type和flags參數(shù),在后面分別配置了
mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
        | LayoutParams.FLAG_NOT_FOCUSABLE
        | LayoutParams.FLAG_SHOW_WHEN_LOCKED;
mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
mFloatingButton.setOnTouchListener(this);
mWindowManager.addView(mFloatingButton, mLayoutParams);

flags參數(shù)解析:

FLAG_NOT_FOCUSABLE:表示window不需要獲取焦點,也不需要接收各種輸入事件。此標記會同時啟用FLAG_NOT_TOUCH_MODAL,最終事件會直接傳遞給下層的具有焦點的window;

FLAG_NOT_TOUCH_MODAL:在此模式下,系統(tǒng)會將window區(qū)域外的單擊事件傳遞給底層的window,當前window區(qū)域內(nèi)的單擊事件則自己處理,一般都需要開啟這個標記;

FLAG_SHOW_WHEN_LOCKED:開啟此模式可以讓W(xué)indow顯示在鎖屏的界面上。 [奇怪的是我刪除這個標記還是在鎖屏看到了添加的組件orz]

type參數(shù)表示window的類型,window共有三種類型:應(yīng)用window,子window和系統(tǒng)window。應(yīng)用window對應(yīng)著一個Activity,子window不能獨立存在,需要附屬在特定的父window之上,比如Dialog就是子window。系統(tǒng)window是需要聲明權(quán)限才能創(chuàng)建的window,比如Toast和系統(tǒng)狀態(tài)欄這些都是系統(tǒng)window,需要聲明的權(quán)限是

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />。

(3)window是分層的,每個window都對應(yīng)著z-ordered,層級大的會覆蓋在層級小的上面,應(yīng)用window的層級范圍是1~99,子window的層級范圍是1000~1999,系統(tǒng)window的層級范圍是2000~2999。

[注意,應(yīng)用window的層級范圍并不是1~999喲]

(4)WindowManager繼承自ViewManager,常用的只有三個方法:addViewupdateViewremoveView

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

(1)Window是一個抽象的概念,不是實際存在的,它也是以View的形式存在。在實際使用中無法直接訪問Window,只能通過WindowManager才能訪問Window。每個Window都對應(yīng)著一個View和一個ViewRootImpl,Window和View通過ViewRootImpl來建立聯(lián)系。

(2)Window的添加、刪除和更新過程都是IPC過程,以Window的添加為例,WindowManager的實現(xiàn)類對于addViewupdateViewremoveView方法都是委托給WindowManagerGlobal類,該類保存了很多數(shù)據(jù)列表,例如所有window對應(yīng)的view集合mViews、所有window對應(yīng)的ViewRootImpl的集合mRoots等,之后添加操作交給了ViewRootImpl來處理,接著會通過WindowSession來完成Window的添加過程,這個過程是一個IPC調(diào)用,因為最終是通過WindowManagerService來完成window的添加的。

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

(1)Activity的window創(chuàng)建過程

1.Activity的啟動過程很復(fù)雜,最終會由ActivityThread中的performLaunchActivity來完成整個啟動過程,在這個方法內(nèi)部會通過類加載器創(chuàng)建Activity的實例對象,并調(diào)用它的attach方法為其關(guān)聯(lián)運行過程中所依賴的一系列上下文環(huán)境變量;

2.Activity實現(xiàn)了Window的Callback接口,當window接收到外界的狀態(tài)變化時就會回調(diào)Activity的方法,例如onAttachedToWindow、onDetachedFromWindowdispatchTouchEvent等;

3.Activity的Window是由PolicyManager來創(chuàng)建的,它的真正實現(xiàn)是Policy類,它會新建一個PhoneWindow對象,Activity的setContentView的實現(xiàn)是由PhoneWindow來實現(xiàn)的;

4.Activity的頂級View是DecorView,它本質(zhì)上是一個FrameLayout。如果沒有DecorView,那么PhoneWindow會先創(chuàng)建一個DecorView,然后加載具體的布局文件并將view添加到DecorView的mContentParent中,最后就是回調(diào)Activity的onContentChanged通知Activity視圖已經(jīng)發(fā)生了變化;

5.還有一個步驟是讓W(xué)indowManager能夠識別DecorView,在ActivityThread調(diào)用handleResumeActivity方法時,首先會調(diào)用Activity的onResume方法,然后會調(diào)用makeVisible方法,這個方法中DecorView真正地完成了添加和顯示過程。

ViewManager vm = getWindowManager();
vm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;

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

1.過程與Activity的Window創(chuàng)建過程類似,普通的Dialog的有一個特別之處,即它必須采用Activity的Context,如果采用Application的Context會報錯。原因是Application沒有應(yīng)用token,應(yīng)用token一般是Activity擁有的。[service貌似也有token?]

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

1.Toast屬于系統(tǒng)Window,它內(nèi)部的視圖由兩種方式指定:一種是系統(tǒng)默認的演示;另一種是通過setView方法來指定一個自定義的View。

2.Toast具有定時取消功能,所以系統(tǒng)采用了Handler。Toast的顯示和隱藏是IPC過程,都需要NotificationManagerService來實現(xiàn)。在Toast和NMS進行IPC過程時,NMS會跨進程回調(diào)Toast中的TN類中的方法,TN類是一個Binder類,運行在Binder線程池中,所以需要通過Handler將其切換到當前發(fā)送Toast請求所在的線程,所以Toast無法在沒有Looper的線程中彈出。

3.對于非系統(tǒng)應(yīng)用來說,mToastQueue最多能同時存在50ToastRecord,這樣做是為了防止DOS(Denial of Service,拒絕服務(wù))。因為如果某個應(yīng)用彈出太多的Toast會導(dǎo)致其他應(yīng)用沒有機會彈出Toast。

其他學(xué)習(xí)資料

1.Android應(yīng)用開發(fā)之(WindowManager類使用)

?著作權(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)容