前言
日常开发中,获取xml文件中控件宽度和高度的需要,是我们经常遇到的。但是在Activity的生命周期中获取控件的宽高,onCreate()中获取拿到的值往往是0,在onResume中尝试获取,依旧失败,有一定开发经验的小伙伴都知道,要想得到控件的宽高数据,必须是UI布局执行Measure(),onlayout()之后(具体原因笔者也暂时说不清楚,有待后续补充。。。。。。),才会获取到值,综上所述 Activity 生命周期onResume()执行之前布局文件是没有进行绘制的。由此笔者想深入了解一下Android绘制流程,这就是这篇文件的由来。
先解决上面提到的问题,Activity生命周期过程中,如何获取控件的宽高???
可以在onWindowFocusChanged(boolean hasFocus){}中获取控件的宽高,
另外Activity生命周期方法和View绘制的流程大致如下:
oncreate()→onResume()→onMeasure()→onLayout()→onWidnowFocusChanged()→.....→onDraw()...
参考文档:Android中的onWindowFocusChanged()方法详解
正文
View和Activity相关联的,分析View的绘制过程,往往离不开Activity的分析,所以我们还是先从Activivty的生命周期说起。
ActivityManagerService(简称AMS)是Android 上层系统中比较核心的服务之一,负责系统四大组件的启动,切换,调度以及应用程序的管理和调度等工作。查看源码可知,ActivityThread的main方法是应用程序的入口,main()方法中做一些初始化的工作,包括连接AMS。
另外ActivityThread负责管理Activity,应用所有的Activity都存在ActivityThread中的mActivities集合中。
ActivityThread需要借助ApplicationThread响应AMS的号召,Main()方法中调用attch()方法就是让ApplicationThread和AMS建立联系。
当Activity启动时会先调用到scheduleLaunchActivity()方法,由Handler发送通知消息后执行handleLaunchActivity()->performLaunchActivity()->callActivityOnCreate()->Activity.onCreate()。
onResume()时也一样,当Activity的状态发生改变,经过层层调用执行到handleResumeActivity()方法,在方法中先调用Activity.onResume()方法,再执行WindowManager的addView()方法将Activity的根View(DecorView)添加上去,进而开始绘制流程。这就解释了为什么初次在onResume()方法中获取不到View的宽高。
WindowManagerImpl是WindowManager的实现类,它的addView()方法调用了WindowManagerGlobal的addView()方法。
addView()方法中先创建ViewRootImpl对象,随后执行setView()方法将其和DecorView绑定起来,绘制流程也将由ViewRootImpl()来执行。setView()方法中会执行requestLayout()方法。
requestLayout()方法走下去会异步执行performTraversals()方法,View的三大流程都是在该方法中执行的。到这儿我们算是明白View的绘制流程是从哪儿开始的,这个流程下来,读者看着估计蒙了一比,我写的也比较蒙,尝试着梳理归纳一下吧:
1. ActivityThread.main(基本初始化,attch将ApplocationThread和AMS建立联系)程序入口。
2. 生命周期onCreate()调用过程:Activtiy启动scheduleLaunchActivity()》
handleLaunchActivity()》PerformLaunchActivity()》callActivityCreate()》Activity.onCreate();
3. Activity.onResume()方法执行之后,WindowManager的实现类WindowManagerImpl.addView()中在
调用WindowManagerGlobal.addView()方法,
将根View(DecorView)添加进去。
4. WindowManagerGlobal.addView()方法中,创建ViewRootImpl对象后,执行setView将
ViewRootImpl对象和DecorView绑定,并执行requestLayout方法,该方法会异步执行
performTraversals()方法,View三大绘制流程(measure、layout、draw)就在这个方法中执行
怎么说呢,不看源码,单独看笔者写的这篇文档,看的肯定云里雾里,当看过源码或者源码分析相关博客之后,再回来看这篇文章,算是脱离源码,对这整个流程的一个简单总结,由于笔者能力有限,精力有限,只能尽自己最大的努力,总结自己看到的。下面是笔者对这一部分画的一个简单流程图,更形象些,更容易记住了解整个流程。
View的绘制流程.png
总结
这篇文章算是笔者浏览View绘制相关博客的一些总结,写的比较乱,估计也就是自己能够看懂,能够帮助的其他人最好,只求不要又误导其他的人的地方。另外,笔者想说的是:有些东西看懂了,不一定能写出来,能写出来不一定会用,看过之后,写出来,只为了加深自己的印象,方便以后查看,虽然写的不够好,但是还是要坚持,不坚持写,永远不会有好的结果,坚持下去,才会有有可能开花结果,毕竟越努力越幸福
网友评论