Activity,Window与View三者之间的关系如何?

源码分析基于Android29进行。

上一篇文章,我们分析了Activity#setContentView()方法是怎么将页面加载出来的icon-default.png?t=M1L8https://blog.csdn.net/zxm528/article/details/123134387?spm=1001.2014.3001.5501,我们知道了布局文件通过mContentParent加载到了DecorView中,以及布局文件是在什么时机变为可见的。那么你是否清楚DecorView是怎么关联Activity的,以及DecorView和Window的关系?

书接上回,我们通过阅读Activity的源码清楚,每一个Activity都有且仅有一个Window对象,这里是PhoneWindow,也是Window的唯一实现类下面我们就从源码角度分析一下上述三者之间的关系。

上一篇文章我们知道Activity#handleResumeActivity()方法,通过一系列的方法调用最终我们设置的布局由不可见变为可见状态,我们来看一下该方法的源码:

如上图所示位置2处源码,r为ActivityClientRecord的实例,a为Activity实例,通过a.getWindowManager()获取了WindowManager对象实例。位置3处,当Activity#mVisibleFromClient变量为true时,也就是Activity对应的WindowManager已经调用了对应的addView方法。当我们就需要分析一下这里的WindowManager是怎么初始化的。说道这个读过上一篇文章的小伙伴应该有印象,在Activitiy#attach()方法里有Window和WindowManager的初始化逻辑。我们来看一下:

上述代码首先是初始化Window对象mWindow,然后通过mWindow.setWindowManager()方法,为当前的mWindow对象设置WindowManager。然后在下面的代码中“mWindowManager=mWindow.getWindowManager()”获取了mWindow的WindowManager对象。很显然,上面的setWindowManager()方法,应该有初始化WindowManager的相关逻辑。我们深入看一下:

果不其然,在该方法内部初始化了WindowManager对象,也就是说我们通过Activity#getWindowManager()获取的WindowManager对象都是WindowManagerImpl的实例。到了这里不知道大家有没有这个疑问?不是已经通过wm=(WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)获得了WindowManager方法了为什么还有通过WindowManagerImpl#createLocalWindowManager()方法再初始化一次呢这个问题我们先不进行回答,我们接着看一下WindowManagerImpl#createLocalWindowManager()这个方法

 

进入WindowManagerImpl我们看到它是WindowManager的实现类,我们了解到这个类是用来让我们更好的和系统的窗口管理器(System Window Manager)进行通信,我们似乎理解了为什么这么实现了。目前的猜测是,通过实现了WindowManager接口的WindowManagerImpl我们可以更好的进行Activity于View的通信。具体怎么样我们继续往下看吧。在WindowManagerImpl类的源码里我们看到了WindowManagerGlobal的实例对象“mGlobal”,其中WindowManagerGlobal是单例模式的。到了这里我们回想一下上面说的Activity#handleResumeActivity()方法里的位置3处的"wm.addView()"方法,其具体实现是WindowManagerImpl里面,我们看一下:

我们看到是通过mGlobal的addView方法实现的,其中mParentWindow是前面Activity#attach()方法里面的mWindow对象,也就是PhoneWindow.下面我们就看一下WindowManagerGlobal类的addView()方法:

位置1处是,WindowManagerGlobal在执行addView()之前,会通过findViewLocked()方法查询一下当前DecorView是否已经添加过,如果添加过的话index>=0,否则index=-1.如果已经添加过,那么会执行doDie()方法,该方法就是将当前view从队列移除并执行window移除view的逻辑(dispatchDetachedFromWindow()).下面我们看位置2处的代码,首先是创建了ViewRootImpl的对象实例root,然后通过调用root.setView()方法,将DecorView设置进了ViewRootImpl中。

进入ViewRootImpl类,首先是类注释解释道:该类是视图树的顶层,实现了View和WindowManager之间所需的协议。该类是最大程度的对WindowManager细节的实现。下面我们还是看一下ViewRootImpl#setView的具体实现细节:

 位置1处,requestLayout()方法调用,View控件将会进行绘制相关逻辑,该方法的调用将会在添加到Window之前进行第一次布局,以保证当收到其他系统事件时会进行重新绘制。位置2处,是WindowSession是WindowManagerGlobal中的单例类型,sWindowSession是IWindowSession类型,实际上是IBinder类型。位置2处就是AIDL获取IWindowSession对象。

总结一下:

1.Activity是直接和用户进行信息交流的页面控件,每一个Activity都有一个Window对象,也就是PhoneWindow的实例对象。Activity通过getWindowManager()获取的WindowManager对象都是WindowManagerImpl实例。

2.每一个Window对象(PhoneWindow实例)对应于一个DecorView,DecorView作为Window的根View,页面的布局添加到了mContentParent(DecorView为父布局,id为android.R.id.content)中。同时每一个Window对象都是被WindowManagerImpl管理。WindowManagerGlobal作为唯一单例将Window和View通过ViewRootImpl联系起来。

3.DecorView是Window中布局的根布局,管理者Activity页面的绘制等功能。而ViewRootImpl是视图树的顶层控件,但是它不是View的子类,通过setView方法将当前Window添加进去,剩下的渲染等逻辑就交给了WMS进行。

上面我还留给大家一个问题,就是:为什么还有通过WindowManagerImpl#createLocalWindowManager()方法再初始化一次呢到此我们就把三者之间的关系说完了,由于笔者能力有限,不足之处希望大家给出宝贵意见,一起学习一起成长。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心灵行者

你的鼓励是我最大的创作动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值