Android的图形之美(一)

在Android App中,我们经常会看到页面与页面之间的切换,页面弹出输入法以及页面弹出窗口等,这种情况实际就是一个Activity中对应了一个窗口,页面之间的切换既是Activity生命周期的调用,也是两个窗口之间哪个展示在前,同理的,输入法也是一个窗口,在页面弹出的也是一个子窗口,由此得出,在Android系统中,我们需要一个管理类用来管理窗口的,而这就是我们经常看到的WindowManagerService(WMS)服务发挥的作用。各个Activity对应的Window的状态实际由WindowState来管理。我们在启动Activity的时候,实际上就涉及应用程序侧——WMS——AMS三者之间的关联,如下图所示:

我们在Activity启动一节提到,Activity组件的启动由AMS来管理,和Activity组件启动相关的对象有包括ActivityRecord,用来记录Activity运行状态。我们在开发过程中,经常出现在弹出弹窗时,提示相关弹窗token不存在的情况,这个bug暂且不追究什么原因引起,我们只要知道,窗口是需要对应一个token的,在Activity中,对应有个AppWindowToken,其在Activity启动的过程中由WMS创建,既然Activity有多个,而AppWindowToken是由WMS创建的,可想而知,AppWindowToken一定是记录在一个Collections中,如Hashmap,list等。AppWindowToken的作用实际就是一个标识符,且和Activity是唯一对应的。为啥需要AppWindowToken,实际上因为有WMS和AMS相互参与,因此使用唯一的token来标记对应的Activity就显得有必要。

IWindow和IWindowSession都为Binder本地对象,用于应用程序和WMS之间的相关调用。通过IWindowSession通过WMS为Activity创建一个WindowState对象(WindowState的作用下面会说到),通过调用IWindowSession的relayout来请求Activity进行UI布局,使得Activity可以在屏幕上显示。IWindow具体对象引用在WMS创建的WindowState的mClient属性中,通过这个属性,当Activity窗口大小、可见性、焦点等变化的时候,通过IWindow的相关方法通知到Activity,从而进行对应的调整。

此外,WMS在为Activity创建一个WindowState过程中,通过调用attach方法创建了Java层的SufaceSession对象,Java层的SurfaceSession对象对应用C++层的SurfaceComposerClient对象,因此Java层的应用程序就可以通过SurfaceSession来和SurfaceFlinger建立了联系。

那么窗口有了,正如一扇窗的框架有了,但是我们需要安装的是玻璃,否则,窗只是个框架,没有任何实质的东西,因此,形如Activity的内容正是一扇窗的玻璃。那么这个窗玻璃究竟有哪些知识点呢?

我们知道,Activity启动的流程中,也是创建UI界面的过程,既窗口的绘图表面。窗口的绘图表面实际涉及到几个数据结构。

ViewRoot(ViewRootImpl)——通过它可以对UI进行刷新布局、重新渲染等;

WindowManagerImpl(WindowManagerGloable)——本地窗口的管理器,本地成员包括三个重要的数组,mViews、mRoots、mParams。用于存储每个窗口对应的UI页面、UI页面对应的指导者viewRoot以及相关的布局;

PhoneWindow——为Activity在启动过程中创建的本地窗口对象;

DecorView——所有应用窗口的父View,包括titleBar和contentView,一般情况下,Activity在onCreate的时候setContentView即设置contentView的UI内容。

这样,我们知道了Activity启动的时候创建了本地窗口phoneWindow, PhoneWindow包含DecorView,该View我们主要的开发点就是contentView,通过contentView开发者可以实现具体需求需要的。本地窗口以及相关的UI View有了,前面说的在Activity启动的时候,创建并设置相关的view过程中会进行WindowState的对象创建。View有了,窗口管理有了,这些可以看成是软件上的,那么怎么变现到显示屏展示呢?我们继续以玻璃窗为例子,有窗为框架了,我们玻璃造型也知道怎么处理了,但是我们需要介子去把这些内容展示出来。而这就是我们常看到的Surface。如下图所示,每个应用程序窗口都对应有两个Java层的Surface对象,其中一个是在WMS服务这一侧创建的,而另一个是在应用程序进程这一侧创建的。在WMS服务这一侧创建的Java层的Surface对象关联C++层的SurfaceControl,用来设置应用窗口的属性、例如大小、位置等,而在应用程序这一侧创建的Java层的Surface对象关联C++层的Surface对象,用来绘制应用程序窗口的UI,既应用程序窗口的绘图表面,而最终,UI图形界面都关联到用到SurfaceFling服务提供的同一个Layer对象。对于SurfaceFling,还是如同上面,将一步步揭开是什么来的。

既然我们已经找到了承载体Surface,那么接下来我们来看下应用程序是如何绘制上去的,绘制上去之后,SurfaceFlinger又是怎样提供一个能力让相关的UI展示到显示屏上的。

应用程序的绘制流程在应用层面上来看就是Android的绘制原理,经过onMeasure(窗口的测量)、onLayout(窗口的布局)、onDraw(窗口的绘制)。在onDraw这一步,ViewRoot(ViewRootImpl)首先会创建一个Canvas画布,接着在画布上绘制Android程序创建的的UI, 最后再将已画上内容的画布(Canvas)交给SurfaceFlinger服务来进行渲染。在onDraw这一步,可以区分是硬件加速(使用openGL)还是非硬件加速(使用Skia图形库)来进行栅格化。通过绘制在Canvas画布上一个图形缓存区中,进而SurfaceFlinger通过OpenGL图像块API来将这个图形缓冲区渲染到帧缓冲区中,既绘制到屏幕上。如下图软件绘制和硬件绘制的区别。

在Android3.0或者没有启动硬件加速之前,系统启用软件的方式流程如下:

从Android3.0开始,就可以支持硬件加速,Android4.0开始,默认开启硬件加速,如下图。

我们知道,Android设备的显示屏是用来显示画面的。而应用程序的UI就是渲染在显示屏上的。在内核空间,系统屏幕是一个称为帧缓冲区的硬件设备来描述的。在用户空间,用户空间通过文件描述符形如/dev/graphics/fbn(其中n可为0、1...n)来操作硬件设备。涉及到硬件设备,在HAL究竟是干嘛的一文中说到,硬件抽象层是对硬件设备一种抽象,所谓抽象就是计算机语言结构化,如对应设备的结构体,对应操作的方法等。所以帧缓存区的硬件设备不是真正的硬件设备,实际真正的设备是显卡,通过帧缓存区的映射设备描述(硬件抽象层),可以访问显卡或者显卡的寄存器等。

Android系统在帧缓冲区中提供了一个Gralloc模块,封装了帧缓冲区的所有访问操作。用户空间应用程序在使用帧缓冲区的时候,首先要加载Gralloc模块之后,并且获得一个gralloc设备和fb设备。gralloc设备的作用是应用程序可以通过它申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间,从而就可以往里面写入要绘制的内容了。用户空间通过fb设备把前面已经准备的图形缓冲区渲染到帧缓冲区中,既将图形缓冲区绘制到屏幕上。

至此,我们就了解了应用程序的窗口是如何管理了,应用程序的窗口UI是如何绘制的,以及是如何绘制到窗口的绘制表面的,进而在屏幕上显示的。接下来我们围绕SurfaceFlinger服务,展开分析关于缓冲区的问题,以及UI渲染同步机制问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容