一场Toast引发的血案---WindowManager

在一场Toast引发的血案—Toast的显示中,已经大致了解了Toast的显示过程,但是还是有很多疑惑,Toast最终现实的时候是要通过WindowManager添加到一个Window的,但是这个WindowManager是哪个WindowManager,带着这个疑惑,我们开始深入。

可能在此之前对Window不是很了解,但这不影响对WindowManager的理解,只需要大概知道一个Activity,一个Dialog在显示的时候对应这一个Window即可。

WindowManger对象的产生

要使用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我会在后面单独分析。

WindowManager的获取

上面分析了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是由WindowManagerImplcreateLocalWindowManager方法产生的,而createLocalWindowManager最终会调用

return new WindowManagerImpl(mContext, parentWindow);

突然感觉有回到了上一部分。

有了Activity的教训,我赶紧去看了ServiceApplicaiton,最终确认没有都是直接调用了ContextImplgetSystemService方法,并没有对服务进行特殊的处理。

总结

上面分析了WindowManager的产生和获取,可以发先每个context都可以获取自己的WindowManager实例,以便对Window进行操作,但是WindowManager实例实际上是通过WindowManagerGlobal的单利对象对Window进行操作的。

你可能感兴趣的:(android,framework,android,framework)