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

xiaoxiao2021-02-28  46

在一场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<WindowManager>() { @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是由WindowManagerImpl的createLocalWindowManager方法产生的,而createLocalWindowManager最终会调用

return new WindowManagerImpl(mContext, parentWindow);

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

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

总结

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

转载请注明原文地址: https://www.6miu.com/read-2624209.html

最新回复(0)