在一场Toast引发的血案—Toast的显示中,已经大致了解了Toast的显示过程,但是还是有很多疑惑,Toast最终现实的时候是要通过WindowManager添加到一个Window的,但是这个WindowManager是哪个WindowManager,带着这个疑惑,我们开始深入。
可能在此之前对Window不是很了解,但这不影响对WindowManager的理解,只需要大概知道一个Activity,一个Dialog在显示的时候对应这一个Window即可。
要使用WindowManger必须要获取WindowManger,获取WindowManger是通过context.getSystemService(Context.WINDOW_SERVICE)
,但是WindowManager对象究竟是怎么产生的呢?在ContextImpl
中看到了下面的代码:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
再跟踪到SystemServiceRegistry
中发现了下面的代码:
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
感觉这和我的理解不太一样,WindowManager不应该是一个单例吗?再到WindowManagerImpl
中看下。突然发现了下面的代码:
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
在我们经常使用的addView
函数中也有mGlobal
:
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
......
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
removeView
函数就直接使用了mGlobal.removeView
public void removeView(View view) {
mGlobal.removeView(view, false);
}
@Override
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
到这里,我们已经知道每个WindowManager的实例都不一样,但是每部都是在使用WindowManagerGlobal
的单利对象对Window上的控件进行管理。为了不影响对Toast的分析,WindowManagerGlobal
我会在后面单独分析。
上面分析了WindowManger对象的产生,接下来就要分析下WindowManager对象的获取。在没有看相关源码之前,我一直以为context.getSystemService(Context.WINDOW_SERVICE)
在那都是一样的,可以不用特别关注context
的区别,直到我在Activity
中看到了下面的代码:
public Object getSystemService(@ServiceName @NonNull String name) {
......
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
wc,Activity
还针对getSystemService
进行了特殊处理,如果是为了获取WindowManager或者SearchManager,就会去拿Activity
的属性mWindowManager
。看下mWindowManager
是如何产生的
代码段1
mWindow = new PhoneWindow(this, window, activityConfigCallback);
代码段2
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
代码段3
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);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
发现最终mWindowManager
是由WindowManagerImpl
的createLocalWindowManager
方法产生的,而createLocalWindowManager
最终会调用
return new WindowManagerImpl(mContext, parentWindow);
突然感觉有回到了上一部分。
有了Activity
的教训,我赶紧去看了Service
和Applicaiton
,最终确认没有都是直接调用了ContextImpl
的getSystemService
方法,并没有对服务进行特殊的处理。
上面分析了WindowManager
的产生和获取,可以发先每个context都可以获取自己的WindowManager
实例,以便对Window
进行操作,但是WindowManager
实例实际上是通过WindowManagerGlobal
的单利对象对Window进行操作的。