前言
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ù)探索》