Android解析WindowManager(一)WindowManager體系

前言

WindowManagerService(WMS)和AMS一樣猜丹,都是Android開發(fā)需要掌握的知識點(diǎn),同樣的硅卢,WMS也很復(fù)雜射窒,需要多篇文章來進(jìn)行講解,為何更好的理解WMS将塑,首先要了解WindowManager脉顿,這一篇我們來學(xué)習(xí)WindowManager體系。

1.Window点寥、WindowManager和WMS

Window我們應(yīng)該很熟悉艾疟,它是一個(gè)抽象類,具體的實(shí)現(xiàn)類為PhoneWindow敢辩,它對View進(jìn)行管理蔽莱。 WindowManager是一個(gè)接口類,繼承自接口ViewManager戚长,從名稱就知道它是用來管理Window的盗冷,它的實(shí)現(xiàn)類為WindowManagerImpl。如果我們想要對Window進(jìn)行添加和刪除就可以使用WindowManager同廉,具體的工作都是由WMS來處理的仪糖,WindowManager和WMS通過Binder來進(jìn)行跨進(jìn)程通信柑司,WMS作為系統(tǒng)服務(wù)有很多API是不會暴露給WindowManager的,這一點(diǎn)與ActivityManager和AMS的關(guān)系有些類似锅劝。
關(guān)于WMS的功能攒驰,會在后續(xù)文章進(jìn)行介紹,這里我們只需要知道它的主要功能包括Window管理和輸入系統(tǒng)就可以了故爵。這一系列文章的重點(diǎn)是WindowManager玻粪。
Window、WindowManager和WMS的關(guān)系可以簡略的用下圖來表示稠集。


Window包含了View并對View進(jìn)行管理奶段,Window用虛線來表示是因?yàn)閃indow是一個(gè)抽象概念,并不是真實(shí)存在剥纷,Window的實(shí)體其實(shí)也是View痹籍。WindowManager用來管理Window,而WindowManager所提供的功能最終會由WMS來進(jìn)行處理晦鞋。

2.WindowManager體系

接下來我們從源碼角度來分析WindowManager體系以及Window和WindowManager的關(guān)系蹲缠。
WindowManager是一個(gè)接口類,繼承自接口ViewManager悠垛,ViewManager中定義了三個(gè)方法线定,分別用來添加、更新和刪除View:
frameworks/base/core/java/android/view/ViewManager.java

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

WindowManager也繼承了這些方法确买,而這些方法傳入的參數(shù)都是View斤讥,說明WindowManager具體管理的是以View形式存在的Window。WindowManager在繼承ViewManager的同時(shí)湾趾,又加入很多功能芭商,包括Window的類型和層級相關(guān)的常量、內(nèi)部類以及一些方法搀缠,其中有兩個(gè)方法是根據(jù)Window的特性加入的铛楣,如下所示。

    public Display getDefaultDisplay();
    public void removeViewImmediate(View view);

getDefaultDisplay方法會得知這個(gè)WindowManager實(shí)例將Window添加到哪個(gè)屏幕上了艺普,換句話說簸州,就是得到WindowManager所管理的屏幕(Display)。removeViewImmediate方法則規(guī)定在這個(gè)方法返回前要立即執(zhí)行View.onDetachedFromWindow()歧譬,來完成傳入的View相關(guān)的銷毀工作岸浑。關(guān)于Window的類型和層級會在本系列后續(xù)的文章進(jìn)行介紹。
Window是一個(gè)抽象類瑰步,它的具體實(shí)現(xiàn)類為PhoneWindow助琐。在Activity啟動過程中會調(diào)用ActivityThread的performLaunchActivity方法,performLaunchActivity方法中又會調(diào)用Activity的attach方法面氓,如果不了解這些請查看Android深入四大組件(一)應(yīng)用程序啟動過程(后篇)這篇文章兵钮。
我們從Activity的attach方法開始入手,如下所示舌界。
frameworks/base/core/java/android/app/Activity.java

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);
        mFragments.attachHost(null /*parent*/);
        mWindow = new PhoneWindow(this, window);//1
        ...
         /**
         *2
         */
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
      ...

注釋1處創(chuàng)建了PhoneWindow掘譬,在注釋2處調(diào)用了PhoneWindow的setWindowManager方法,這個(gè)方法的具體的實(shí)現(xiàn)在PhoneWindow的父類Window中呻拌。
frameworks/base/core/java/android/view/Window.java

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    mAppToken = appToken;
    mAppName = appName;
    mHardwareAccelerated = hardwareAccelerated
            || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);//1
    }
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);//2
}

如果傳入的WindowManager為null葱轩,就會在注釋1處調(diào)用Context的getSystemService方法,并傳入服務(wù)的名稱Context.WINDOW_SERVICE("window")藐握,具體的實(shí)現(xiàn)在ContextImpl中靴拱,如下所示。
frameworks/base/core/java/android/app/ContextImpl.java

@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

@Override
public String getSystemServiceName(Class<?> serviceClass) {
    return SystemServiceRegistry.getSystemServiceName(serviceClass);
}

最終會調(diào)用SystemServiceRegistry的getSystemServiceName方法猾普。
frameworks/base/core/java/android/app/SystemServiceRegistry.java

  public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
    }

SYSTEM_SERVICE_NAMES是一個(gè)HashMap類型的數(shù)據(jù)袜炕,它用來存儲服務(wù)的名稱,那么傳入的Context.WINDOW_SERVICE到底對應(yīng)著什么初家?我們接著往下看偎窘。
frameworks/base/core/java/android/app/SystemServiceRegistry.java

final class SystemServiceRegistry {
...
 private SystemServiceRegistry() { }
 static {
 ...
   registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
...
 }
}

SystemServiceRegistry 的靜態(tài)代碼塊中會調(diào)用多個(gè)registerService方法,這里只列舉了和本文有關(guān)的一個(gè)溜在。registerService方法會將傳入的服務(wù)的名稱存入到SYSTEM_SERVICE_NAMES中陌知。從上面代碼可以看出,傳入的Context.WINDOW_SERVICE對應(yīng)的就是WindowManagerImpl實(shí)例掖肋,因此得出結(jié)論仆葡,Context的getSystemService方法得到的是WindowManagerImpl實(shí)例。我們再回到Window的setWindowManager方法志笼,在注釋1處得到WindowManagerImpl實(shí)例后轉(zhuǎn)為WindowManager類型沿盅,在注釋2處調(diào)用了WindowManagerImpl的createLocalWindowManager方法:

frameworks/base/core/java/android/view/WindowManagerImpl

 public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

createLocalWindowManager方法同樣也是創(chuàng)建WindowManagerImpl,不同的是這次創(chuàng)建WindowManagerImpl時(shí)將創(chuàng)建它的Window作為參數(shù)傳了進(jìn)來籽腕,這樣WindowManagerImpl就持有了Window的引用嗡呼,就可以對Window進(jìn)行操作,比如
在Window中添加View皇耗,來查看WindowManagerImpl的addView方法:
frameworks/base/core/java/android/view/WindowManagerImpl

   @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);//1
    }

注釋1處調(diào)用了WindowManagerGlobal的addView方法南窗,其中最后一個(gè)參數(shù)mParentWindow就是Window,可以看出WindowManagerImpl雖然是WindowManager的實(shí)現(xiàn)類郎楼,但是卻沒有實(shí)現(xiàn)什么功能万伤,而是將功能實(shí)現(xiàn)委托給了WindowManagerGlobal,這里用到的是橋接模式呜袁。關(guān)于在Window中添加View敌买,本系列后續(xù)的文章會詳細(xì)介紹。
我們來查看WindowManagerImpl中如何定義的WindowManagerGlobal:
frameworks/base/core/java/android/view/WindowManagerImpl

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Context mContext;
    private final Window mParentWindow;//1
...
  private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        mParentWindow = parentWindow;
    }
 ...   
}

可以看出WindowManagerGlobal是一個(gè)單例阶界,說明在一個(gè)進(jìn)程中只有一個(gè)WindowManagerGlobal實(shí)例虹钮。注釋1處說明WindowManagerImpl可能會實(shí)現(xiàn)多個(gè)Window聋庵,也就是說在一個(gè)進(jìn)程中WindowManagerImpl可能會有多個(gè)實(shí)例。

通過如上的源碼分析芙粱,Window和WindowManager的關(guān)系如下圖所示祭玉。

PhoneWindow繼承自Window,Window通過setWindowManager方法與WindowManager發(fā)生關(guān)聯(lián)春畔。WindowManager繼承自接口ViewManager脱货,WindowManagerImpl是WindowManager接口的實(shí)現(xiàn)類,但是具體的功能都會委托給WindowManagerGlobal來實(shí)現(xiàn)律姨。

參考資料
《深入理解Android 卷1》
《深入理解Android 卷3》
《深入理解Android內(nèi)核設(shè)計(jì)思想》第二版
《Android開發(fā)藝術(shù)探索》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末振峻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子择份,更是在濱河造成了極大的恐慌扣孟,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缓淹,死亡現(xiàn)場離奇詭異哈打,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)讯壶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門料仗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伏蚊,你說我怎么就攤上這事立轧。” “怎么了躏吊?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵氛改,是天一觀的道長。 經(jīng)常有香客問我比伏,道長胜卤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任赁项,我火速辦了婚禮葛躏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘悠菜。我一直安慰自己舰攒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布悔醋。 她就那樣靜靜地躺著摩窃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芬骄。 梳的紋絲不亂的頭發(fā)上猾愿,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天鹦聪,我揣著相機(jī)與錄音,去河邊找鬼匪蟀。 笑死椎麦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的材彪。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼琴儿,長吁一口氣:“原來是場噩夢啊……” “哼段化!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起造成,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤显熏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后晒屎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喘蟆,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年鼓鲁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蕴轨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骇吭,死狀恐怖橙弱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情燥狰,我是刑警寧澤棘脐,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站龙致,受9級特大地震影響蛀缝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜目代,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一屈梁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧像啼,春花似錦俘闯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至僧诚,卻和暖如春遮婶,著一層夾襖步出監(jiān)牢的瞬間蝗碎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工旗扑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蹦骑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓臀防,卻偏偏與公主長得像眠菇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子袱衷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容