前面的两篇博客,总结了一下Window的基本知识,我们知道Window是一个抽象的概念,每一个Window都对应着一个View,Window的呈现方式是View,View要依赖Window,View和Window最终要关联在一起。Activity在android中所起的作用主要是处理一些逻辑问题,比如生命周期的管理、建立窗口等。Window的层次关系就如下面画的一样。详细参考前面两篇博客。
Android源码解析Window系列第(一)篇—Window的基本认识和Activity的加载流程
Android源码解析Window系列第(二)篇—Dialog加载绘制流程
这篇博客写一下WindowManager,在android中,窗口的管理还是比较重要的一块,因为他直接负责把内容展示给用户,并和用户进行交互。响应用户的输入等。WindowManager可以说是外部访问Window的入口,利用WindowManager可以向Window中添加View,删除View,更新View。其实我们已经用过很多次WindowManager的addView方法了,因为ViewGroup就继承了ViewManager,WindowManager也是继承了ViewManager。再比如360手机助手有一个悬浮窗,用来显示内存的实时信息,这个也要通过WindowManager来处理。
1、WindowManager基本认识
- WindowManager可以通过下面两种方式进行获取。
WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager mWindowManager=(WindowManager) getWindowManger();
- 设置WindowManager.LayoutParams参数
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
// 设置window type
wmParams.type = LayoutParams.TYPE_PHONE;
// 设置图片格式,效果为背景透明
wmParams.format = PixelFormat.RGBA_8888;
// 调整悬浮窗口至右侧中间
wmParams.gravity = Gravity.RIGHT| Gravity. CENTER_VERTICAL;
// 以屏幕左上角为原点,设置x、y初始值
wmParams.x = 0;
wmParams.y = 0;
// 设置悬浮窗口长宽数据
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height =WindowManager.LayoutParams.WRAP_CONTENT;
- WindowManager是一个接口,并且继承了ViewManager
public interface WindowManager extends ViewManager
WindowManager.LayoutParams内部包含了Window的一些参数,比如Window的宽高,对齐方式,flag等。
WindowManager是外界访问Window的入口,Window的具体实现是WindowManagerService,WindowManager和WindowManagerService的交互是一个IPC过程。
- Android中所有的视图都是通过Window呈现的,不管是Activity、Dialog还是Toast,他们的视图实际上都是附加在Window上的,因此Window实际是View的直接管理者。
2、Window中添加View
既然WindowManager是外部访问Window的入口,对于Activity的Window来说,WindowManager肯定是可以访问Activity的Window的,想往Activity中的DecorView添加View,Activity应改持有了WindowManager的引用,在第一篇博客中,有分析过,在ActivityThread中的performLaunchActivity内部用反射的方式创建了Activity对象之后,调用了Activity对象的attach方法。
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);
....
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
....
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
attach内部创建了PhoneWindow之后,以(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)的方式获取了WindowManager对象,并且设置给了Window中的mWindowManage成员变量。
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);
}
//返回的是WindowManagerImpl
mWindowManager =((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
//可以判断出WindowManagerImpl是WindowManager的实现类
return new WindowManagerImpl(mContext, parentWindow);
}
然后以mWindow.getWindowManager()方式给Activity的mWindowManager赋值,到此Activity持有了mWindowManager对象,mWindow对象,Window也持有了mWindowManager对象,Activity类的Window类型成员变量mWindow及WindowManager类型成员变量mWindowManager都被赋值,现在可以操作Activity的Window了。
现在分析一下WindowManager是如何操作Window中的View的,WindowManager继承了ViewManager,ViewManager定义了三个操作View的方法。addView/updateViewLayoutView/removeView,所以ViewManager像是定义了一套外部操作Activity的Window中的View的接口。
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的真正实现类是WindowManagerImpl
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
......
public WindowManagerImpl(Display display) {
this(display, null);
}
private WindowManagerImpl(Display display, Window parentWindow) {
mDisplay = display;
mParentWindow = parentWindow;
}
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
......
}
WindowManagerImpl虽然带着Impl的后缀,却把活都交给了mGlobal,这样就要去看看WindowManagerGlobal的addView了。
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
//参数校验省略
......
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
if (parentWindow != null) {
//如果是子View,需要调整布局参数
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent and we're running on L or above (or in the
// system context), assume we want hardware acceleration.
final Context context = view.getContext();
if (context != null
&& context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
......
//第一步
root = new ViewRootImpl(view.getContext(), display);
//第二步
view.setLayoutParams(wparams);
//第三步
mViews.add(view);
//第四步
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
//第五步
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
上面的代码主要有五个步骤
- 1、构建ViewRootImpl,暂时不管ViewRootImpl是什么东西
- 2、给所添加的View设置参数
- 3、保存View到mViews的列表中
- 4、保存ViewRootImpl对象root到mRoots的列表中
- 5、调用ViewRootImpl对象root的setView方法,将View显示到手机上。setView方法比较复杂,已经深入到Native层了,不分析了。
3、WindowManager获取方式的分析
WindowManager w1 = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager w2 = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
上面的w1与w2有什么区别呢?
w1获取是通过Context的getSystemService方法,这个方法的实现在Activity中,返回的是Activity的mWindowManager。
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
//此处返回的是Activity的mWindowManager
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
此处返回的Activity的mWindowManager是通过createLocalWindowManager来创建的,注意传入给WindowManagerImpl中参数parentWindow,就是当前Window对象。
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
因为Activity有多个,所以每个Activity的WindowManager都不一样。而w2的获取的WindowManager,最终WindowManagerImpl时传入给WindowManagerImpl中parentWindow是null值,这获取的WindowManager对每个APP来说是全局单例的。
4、 Window在事件分发中的应用
当一个点击事件产生时,它首先传递到Activity、在Activity的dispatchToucheEvent的方法中进行分发、然后传递到Window、最后才到顶级view。
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
查看Window子类PhoneWindow的源码。
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
而这里的mDecor就是顶级View,就这样事件就从window传递到了顶级View了。
Please accept mybest wishes for your happiness and success!