標籤:記憶體回收 date 接管 pos die ams dispatch new 步驟
No1:
Window是一個抽象類別,它的具體實現是PhoneWindow。建立一個Window是很簡單的事,只需要通過WindowManager即可完成。
WindowManager是外界訪問Window的入口,Window的具體實現位於WindowManagerService中,WindwoManager和WindowManagerService的互動時一個IPC過程。
Android中所有的視圖都是通過Window來呈現的,因此Window實際是View的直接管理者。
單機事件由Window傳遞給DecorView,然後再由DecorView傳遞給我們的View。
No2:
Window有三種類型,分別是應用Window、子Window和系統Window。
應用Window--一個Activity
子Window--不能單獨存在,需要附屬在特定的父Window中,比如Dialog
系統Window--是需要聲明許可權才能建立的Window,比如Toast和系統狀態列
No3:
Window是分層的,每個Window都有對應的z-ordered,層級大的會覆蓋在層級小的Window的上面。
應用程式層Window層級範圍1~99
子Window層級範圍1000~1999
系統Window層級範圍2000~2999
這些層級範圍對應著WindowManager.LayoutParams的type參數。如果想要Window位於所有Window的最頂層,那麼採用較大的層級即可。
No4:
WindowManager所提供的功能很簡單,常用的只有三個方法,添加ViewaddView、更新ViewupdateViewLayout和刪除ViewremoveView,這三個方法定義在ViewManager中,而WindowManager繼承了ViewManager。
No5:
可以拖動的Window效果
public boolean onTouch(View v,MotionEvent event){ int rawX = (int)event.getRawX(); int rawY = (int)event.getRawY(); switch(event.getAction()){ case MotionEvent.ACTION_MOVE: mLayoutParams.x = rawX; mLayoutParams.y = rawY; mWindowManager.updateViewLayout(mFloationButton,mLayoutParams); break; default: break; } return false;}
No6:
Window是一個抽象的概念,每個Window都對應著一個View和一個ViewRootImpl,Window和View通過ViewRootImpl來建立串連,因此Window並不是實際存在的,它是以View的形式存在。
在實際使用中無法直接存取Window,對Window的訪問必須通過WindowManager。
No7:
WindowManager是一個介面,它的真正實現是WindowManagerImpl類。WindowManagerImpl並沒有直接實現Window的三大操作,而是全部交給了WindowManagerGlobal來處理。
WindowManagerImpl這種工作模式是典型的橋接模式。
No8:
Window的添加過程
1.檢查參數是否合法,如果是子Window那麼還需要調整一些布局參數
2.建立ViewRootImpl並將View添加到列表中
3.通過ViewRootImpl來更新介面並完成Window的添加過程
View的繪製過程是由ViewRootImpl來完成的,在setView內部會通過requestLayout完成非同步重新整理請求,scheduleTraversals實際是View繪製的入口,接著會通過WindowSession最終來完成Window的添加過程,真正的實作類別是Session,也就是Window的添加過程是一次IPC調用,在Session內部會調用WindowManagerService來實現Window的添加。
No9:
Window的刪除過程
WindowManagerImpl-->WindowManagerGlobal-->ViewRootImpl
WindowManager中提供了兩種刪除介面removeView和removeViewImmediate,分別表示非同步刪除和同步刪除。
非同步刪除具體的刪除操作由ViewRootImpl的die方法來完成,die發送了一個請求刪除的訊息,ViewRootImpl中的Handler會處理此訊息並調用doDie方法,如果是同步刪除,那麼就不發訊息直接調用doDie方法。
doDie內部會調用dispatchDetachedFromWindow方法,dispatchDetachedFromWindow主要做四件事:
1)記憶體回收相關工作,比如清除資料和訊息、移除回調
2)通過Session的remove方法刪除Window:mWindowSession.remove(mWindow),這同樣是一個IPC過程,最終會調用WindowManagerService的removeWindow方法
3)調用View的dispatchDetachedFromWindow方法,在內部會調用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。
當View從Window中移除時,這個方法就會被調用,可以在這個方法內部做一些資源回收的工作,比如終止動畫、停止線程等
4)調用WindowManagerGolbal的doRemoveView方法重新整理資料,包括mRoots、mParams以及mDyingViews,需要將當前Window所關聯的這三類對象從列表中刪除。
No10:
Window的更新過程:還是要看WindowManagerGlobal的updateViewLayout方法:
1)通過ViewRootImpl的setLayoutParams更新View的LayoutParams並替換掉老的LayoutParams,接著再更新ViewRootImpl中的LayoutParams
2)在ViewRootImpl中會通過scheduleTraversals方法來對View重新布局,包括測量、布局、重繪這三個過程
3)ViewRootImpl還會通過WindowSession來更新Window視圖,最終是由WindowManagerService的relayoutWindow()來具體實現的。同樣是一個IPC過程
No11:
Window對象的建立是通過PolicyManager的makeNewWindow方法實現的。PolicyManager的真正實現是Policy類,所以Window的具體實現的確是PhoneWindow。
No12:
setContentView:Activity-->Window-->PhoneWindow
No13:
DecorView是一個FrameLayout,是Activity中的頂級View,一般包括標題列和內部欄
No14:
Activity的Window的建立過程
PhoneWindow的setContentView步驟
1)如果沒有DecorView,那麼就建立它
2)將View添加到DecorView的mContentParent中(這就是為Activity的setContentView而不叫setView的緣由)
3)回調Activity的onContentChanged方法通知Activity視圖已經發生改變
No15:
在ActivityThread的makeVisible()方法中,首先會調用Activity的onResume方法,接著會調用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和顯示這兩個過程,到這裡Activity的視圖才能被使用者看到。
No16:
Dialog的Window建立過程
1)建立Window
2)初始化DecorView並將Dialog的視圖添加到DecorView中
3)將DecorView添加到Window中並顯示
No17:
普通Dialog有一個特殊之處,就是必須採用Activity的Context,如果採用Application的Context,會報錯沒有token,而應用token一般只有Activity擁有。
系統Window不需要token,因此只要指定對話方塊為Window為系統類別型即可
No18:
Toast具有定時取消這一功能,所以系統採用了Handler。
Toast內部有兩類IPC過程,第一類是Toast訪問NotificationManagerService,第二類是NotificationManagerService回調Toast裡面的TN介面。
顯示和隱藏Toast都需要通過NotificationManagerService來實現,因為NMS運行在系統進程中,所以只能通過遠程調用的方式來顯示和隱藏。TN是一個Binder類,它運行在Binder線程池中,所以需要Handler將其切換到當前線程中,這裡的當前線程是指發送Toast請求所在的線程。
No19:
enqueueToast首先將Toast請求封裝為ToastRecord對象並將其添加到一個名為mToastQueue的隊列中。mToastQueue其實是一個ArrayList。對於非系統應用來說,mToastQueue中最多能同時存在50個ToastRecord。如果不這樣做,將導致其他引用沒有機會彈出Toast。
No20:
Toast延時相應時間後,NotificationManagerService會通過cancelToastlocked方法來隱藏Toast並將其從mToastQueue中移除,這個時候如果mToastQueue中還有其他Toast,那麼NMS就繼續顯示其他Toast。Toast的隱藏也是通過ToastRecord的callback來完成的,這同樣也是一次IPC過程。
No21:
Toast中TN的兩個方法show和hide,是以NMS以跨進程的方式調用的,因此它們運行在Binder線程池中。
《android開發藝術探索》讀書筆記(八)--WindowManager