基础

每一个Activity(包括dialog)都有一个Window对象,而它们显示的布局又是添加到该Window对象中的mDecor中的。而mDecor又是通过WindowManager#addView()才展示出来的。这一点可查看AlertDialog,或者是见ActivityThread中的一部分代码,如下:

            if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();a.mDecor = decor;l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode |= forwardBit;if (a.mVisibleFromClient) {a.mWindowAdded = true;wm.addView(decor, l);}}

这一段代码会在startActivity()时调用,它截自ActivityThread#handleResumeActivity()。

从上面也可看出,它和AlertDialog的处理方式完全一样,直接使用WindowManager#addView(decor,1);。因此,可以知道,要想展示某个View到Window上,必须通过WindowManager#addView()进行。也就是说WindowManager是View展示的桥梁。

WindowManager是接口,通过getSystemService()可知它的具体实现类为WindowManagerImpl。而对于后者,有一成员变量mGlobal指向的是一个WindowManagerGlobal实例,其内部完全是使用WindowManagerGlobal进行操作。

构造函数

Activity#attach()->Window#setWindowManager()->WindowManagerImpl#createLocalWindowManager(this)->WindowManagerImpl#构造函数,在构造函数中为mParentWindow成员变量赋值。

因此,WindowManagerImpl通过mParentWindow指向Window——这个Window对象也是Activity中mWindow指向的Window实例,而Window通过mWindowManager指向WindowManagerImpl实例。

WindowManagerGlobal

单例。其内部有三个变量如下:

    private final ArrayList<View> mViews = new ArrayList<View>();//存储所有addView时的view的private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();//存储所有的ViewRootImpl的private final ArrayList<WindowManager.LayoutParams> mParams =new ArrayList<WindowManager.LayoutParams>();//view对应的LayoutParams,是WindowManager.LayoutParams

有一点要注意:同一index下,它们三个对应的元素是对应的。

addView

代码如下:

public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {//略。对view,display的非空判断。且要求params必须是WindowManager.LayoutParamsfinal WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;//略ViewRootImpl root;View panelParentView = null;synchronized (mLock) {//略//为view设置LayoutParams,并存储root = new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);}try {root.setView(view, wparams, panelParentView);} //略}

逻辑很简单,内容new一个ViewRootImpl,并调用其setView()方法。

getWindowSession

    public static IWindowManager getWindowManagerService() {synchronized (WindowManagerGlobal.class) {if (sWindowManagerService == null) {sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));try {sWindowManagerService = getWindowManagerService();ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());} catch (RemoteException e) {Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);}}return sWindowManagerService;}}public static IWindowSession getWindowSession() {synchronized (WindowManagerGlobal.class) {if (sWindowSession == null) {try {InputMethodManager imm = InputMethodManager.getInstance();IWindowManager windowManager = getWindowManagerService();sWindowSession = windowManager.openSession(new IWindowSessionCallback.Stub() {@Overridepublic void onAnimatorScaleChanged(float scale) {ValueAnimator.setDurationScale(scale);}},imm.getClient(), imm.getInputContext());} catch (RemoteException e) {Log.e(TAG, "Failed to open window session", e);}}return sWindowSession;}}

首先通过getWindoeManagerService()拿到WMS在本进程中的代理对象。分两步:1)通过ServiceManager#getService()拿到WMS在本地的IBinder对象;2)通过asInterface()为IBinder对象创建一个代理类,本进程与WMS的交互就通过该代理类进行。

在getWindowSession()中,通过代理类调用WMS中的openSession(),后者返回的是一个Session对象。所以getWindowSession()返回的是Session对象在本地的代理,而它的具体实例在WMS所属的进程中。

getWindowSession()拿到Session对象的代理类后,就可通过sWindowSession对象访问Session实例中的方法。而Session中,一般的方法都是调用WMS实例完成的(两者属于同一进程,所以通过sWindowSession调用方法相当于间接地调用了WMS中的方法)。因此Session对象是本进程调用WMS的桥梁。

WindowManagerService

addView()->ViewRootImpl#setView()->Session#addToDisplay()->WMS#addWindow()。从addView()到setView()前半部分(到requestLayout()截止),都是对addView()中的View参数进行操作。从setView到最后,却是对Window的显示进行操作。

addWindow

    public int addWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, int viewVisibility, int displayId,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,InputChannel outInputChannel) 

第一个参数为getWindowSession()方法返回值在WMS所在进程中的实例。

第二个参数为IWindow对象,由ViewRootImpl构造函数中创建,在ViewRootImpl#setView()中调用Session#addToDisplay()时将该对象当作参数传递进去,所以WMS进程会得到一个W的代理对象,进而WMS可以使用它调用应用进程中的方法。

attrs为WMG#addView()时View所使用的LayoutParams对象,是由应用进程传递到WMS进程中的。

对于client,addWindow()中有如下代码:

            WindowState win = new WindowState(this, session, client, token,attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

将client又赋值给WindowState#mClient,而WindowState又使用mClient调用应用进程中的方法。由此要知client的作用就是提供一个让WMS调用应用进程中方法的桥梁。

WMS进程由client调用用户进程,而用户进程通过Session对象调用WMS进程。

WindowManagerImpl,WMG与WMS入门相关推荐

  1. Reflex WMS入门系列十七:修改IPG的Grade

    Reflex WMS入门系列十七:修改IPG的Grade Reflex WMS系统里有2个与库存有关的概念,一个是HD,一个是IPG.HD可以简单的理解为托盘,IPG可以理解为放在托盘的物料的库存. ...

  2. Reflex WMS入门系列二十五:将叉车纳入系统进行管理

    Reflex WMS入门系列二十五:将叉车纳入系统进行管理 据笔者所知,SAP WM 模块里是不对仓库里常用的叉车等仓库管理工具进行管理的.笔者发现,Reflex WMS系统则会在很多仓库部门日常操作 ...

  3. Reflex WMS入门系列三十二:导出到Excel

    Reflex WMS入门系列三十二:导出到Excel 如同SAP系统的风格 --- 凡是有list的界面,都能导出到Excel ---, Reflex WMS系统也提供了类似的功能.几乎在任何的Lis ...

  4. Reflex WMS入门系列十八:如何看年终盘点的Inventory report数据?

    Reflex WMS入门系列十八:如何看年终盘点的Inventory report数据? Reflex WMS系统中的盘点分为cycle count(循环盘点)和physical inventory( ...

  5. Reflex WMS入门系列二十二:物料库存报表

    Reflex WMS入门系列二十二:物料库存报表 在Reflex WMS系统上,我们可以通过物料号查询它的HD列表,或者IPG列表.通过在其HD/IPG信息得知其库存数据.当然还可以通过如下方式直接获 ...

  6. Reflex WMS入门系列二十三:几个库存相关的报表

    Reflex WMS入门系列二十三:几个库存相关的报表 Reflex WMS系统作为一个主流的仓库管理软件系统,自然需要对仓库里的库存有多个角度的报表功能.比如常见的slow-moving, agin ...

  7. Reflex WMS入门系列四十:对某个托盘执行上架,系统不能自动建议货架?

    Reflex WMS入门系列四十:对某个托盘执行上架,系统不能自动建议货架? 如下图示,在Reflex WMS系统里,使用RF枪功能,对于某个托盘685110000000041602执行上架操作.Re ...

  8. Reflex WMS入门系列之二十一:关闭一个不需要的盘点

    Reflex WMS入门系列之二十一:关闭一个不需要的盘点 仓库管理实践中,如果业务人员创建好了一个盘点,发现后续暂时不需要执行实际的库存清点工作,或者本次盘点因故取消,或者发现该盘点数据有误需要关闭 ...

  9. Reflex WMS入门系列十二:Reflex里的Location

    Reflex WMS入门系列十二:Reflex里的Location 玩过SAP系统里的人都知道,在SAP系统里库存管理分为IM Level和WM Level.IM Level的仓库,在SAP里被定义为 ...

最新文章

  1. 这才叫细:带你深入理解Redis分布式锁
  2. Knockout 新版应用开发教程之visible绑定
  3. Android快速发布项目到jcenter详解
  4. shell脚本中的引用
  5. 刷题总结——愤怒的小鸟(NOIPDAY2T3)
  6. VTK:移除外表面用法实战
  7. ​北京大学 2022 年博士研究生招生简章
  8. R7-9 模拟EXCEL排序 (25 分)
  9. ApacheCN NodeJS 译文集 20211204 更新
  10. 决策树系列(二)——剪枝
  11. c++ 多字节 转换为 unicode
  12. Windows Xp sp2 升级为 sp3
  13. VS2017 离线安装包下载
  14. android ios emoji表情,iOS和Android的Emoji表情同步方案
  15. 重庆python爬虫培训_PYTHON爬虫工程师
  16. 关于SSL以及https的相关信息
  17. 学习java之java帝国的诞生
  18. 大学计算机实验基础第二版,大学计算机基础实验指导(第2版)
  19. 微信公众平台搜索文章会调用搜狗百科内容?
  20. Jzoj4896 兔子

热门文章

  1. 爬取医药卫生知识服务系统的药品数据——超详细流程
  2. 如何禁止电脑后台自动运行程序
  3. ES6的简单的整理与应用
  4. 手机python3.8.5软件_Python|Python v3.8.7 for Linux下载_网站源码_站长下载
  5. 甲骨文裁撤中国研发中心的背后:不愿为中国培养工程师
  6. zynq system c语言,深度揭秘基于Zynq的开源测试平台火龙果(Red Pitaya)
  7. 警告:Xcode Warning: “no rule to process file
  8. 如何用计算机提高英语水平,英语对计算机专业的重要性及如何提高英语水平
  9. 免于失业的十大软件技术
  10. 小米mix2安兔兔html5跑分,小米MIX 2S跑分多少?高通骁龙845安兔兔跑分实测