Android Framework学习二:Activity创建及View绘制流程
文章目录
- Window绘制流程
- Window Manager Service(WMS)
- Surface
- SurfaceFlinger
- 安卓View层次结构
- Activity
- PhoneWindow
- Activity与PhoneWindow两者之间的关系
- ViewRootImpl
- DecorView
- DecorView 的作用
- DecorView 的结构
- 总结
- Activity创建流程
- View invalidate调用流程
Window绘制流程
在安卓系统中,Window Manager Service(WMS)和 Surface 是与窗口管理和图形显示相关的重要概念。
Window Manager Service(WMS)
- 功能概述:WMS 是安卓系统中负责管理窗口的系统服务。它主要负责窗口的创建、销毁、布局、显示顺序以及与用户交互等方面的管理。
- 工作原理:当一个应用程序创建一个窗口(例如 Activity 的界面)时,它会向 WMS 发送请求。WMS 会为该窗口分配一个唯一的标识,并根据窗口的属性(如大小、位置、层级等)将其添加到窗口管理列表中。在绘制窗口时,WMS 会协调各个窗口的位置和显示顺序,确保它们按照正确的方式显示在屏幕上。当用户进行触摸屏幕等交互操作时,WMS 会根据触摸事件的位置和窗口的布局,将事件分发给相应的窗口进行处理。
Surface
- 概念:Surface 是安卓图形系统中的一个重要概念,它代表了一个可绘制的区域,用于在屏幕上显示图形内容。可以将 Surface 看作是一块画布,应用程序可以在上面绘制各种图形、图像和文本等内容。
- 作用:每个窗口都有一个或多个 Surface 与之关联。当应用程序需要绘制窗口的内容时,它会通过 Surface 来获取绘图的上下文,然后使用图形库(如 OpenGL)在 Surface 上进行绘制。绘制完成后,Surface 会将绘制的结果提交给系统的图形合成器(通常是 Surface Flinger),由图形合成器将各个窗口的 Surface 进行合成,最终显示在屏幕上。
- 与 WMS 的关系:WMS 负责管理窗口的整体布局和显示顺序,而 Surface 则是窗口内容绘制的载体。WMS 会根据窗口的状态和用户的操作,通知应用程序更新其 Surface 的内容。例如,当窗口大小发生变化时,WMS 会通知应用程序重新绘制 Surface 以适应新的大小。同时,WMS 也会与 Surface Flinger 协作,确保各个 Surface 能够按照正确的顺序和方式进行合成和显示。
SurfaceFlinger
SurfaceFlinger是 Android 系统中的一个关键服务,主要负责将不同应用程序的 2D、3D surface 进行组合,并将最终合成的图像发送到显示设备进行显示。
安卓View层次结构
Activity包含PhoneWindow、DecorView、ViewRootImpl等
Activity
Activity属于安卓应用程序的四大组件之一,它为用户提供了一个可视化的界面,让用户能够与应用进行交互。每一个Activity都代表着一个屏幕画面,像是登录界面、主界面等。
在安卓中,Activity是由ActivityManagerService(AMS,活动管理器服务) 创建的 。
以下是Activity的一个简单示例:
import android.app.Activity;
import android.os.Bundle;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}
PhoneWindow
PhoneWindow是Window类的具体实现,Window类在安卓系统里代表着一个顶级的视觉容器,它负责管理窗口的样式、背景以及标题栏等。PhoneWindow主要处理窗口的具体显示逻辑,例如设置窗口的背景、标题栏、内容视图等。
Activity与PhoneWindow两者之间的关系
- 包含关系:Activity包含一个PhoneWindow对象,在Activity的创建过程中,会默认创建一个PhoneWindow对象。
- 视图关联:Activity通过PhoneWindow来设置和管理其视图。Activity的setContentView()方法实际上是调用了PhoneWindow的setContentView()方法。
// Activity类中的setContentView方法
@Override
public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();
}
Activity是用户交互的界面载体,负责处理用户的操作和业务逻辑;PhoneWindow则是窗口的具体实现,负责窗口的显示和管理。它们紧密协作,共同构成了安卓应用程序的用户界面。
ViewRootImpl
- 概述:ViewRootImpl是View与WindowManager之间的桥梁,它不是一个真正的View,但它管理着一个View树的根节点,在Android系统中,每个Window都对应着一个ViewRootImpl实例。
作用 - 视图绘制管理:负责协调View树的绘制过程,包括测量(measure)、布局(layout)和绘制(draw)三个阶段。它会根据屏幕的刷新频率,通过Choreographer来触发视图的重绘,确保界面能够及时更新。
- 事件分发:接收系统传递的输入事件,如触摸事件、按键事件等,并将这些事件分发给View树中的各个View进行处理。它是事件从系统到应用View的重要传递环节。
- 与窗口管理器交互:与WindowManagerService(WMS)进行通信,负责处理窗口的创建、销毁、大小调整等操作。例如,当Activity启动时,ViewRootImpl会与WMS交互来创建窗口,并将DecorView添加到窗口中。
DecorView
在 Android 系统中,DecorView 是窗口(Window)的最顶层视图(顶级 ViewGroup),它作为整个窗口的根视图,包含了系统的装饰(如状态栏、导航栏)和应用程序的内容视图(如 Activity 的布局)。
DecorView 的作用
- 窗口的根容器:每个 Activity 的窗口(PhoneWindow)都包含一个 DecorView,它是 View 层级的最顶层。
- 管理系统 UI:DecorView 负责处理系统窗口装饰(如状态栏、ActionBar/Toolbar)和应用程序内容的协调。
- 内容视图的父容器:开发者通过 setContentView() 设置的布局会被添加到 DecorView 的一个子 ViewGroup(通常是 FrameLayout,ID 为 android.R.id.content)中。
DecorView 的结构
DecorView是每个Activity界面的顶层视图,它是一个FrameLayout。
DecorView 通常包含以下两部分:
- 系统装饰部分
状态栏(Status Bar)、导航栏(Navigation Bar)等系统 UI。
由主题(Theme)控制是否显示(如全屏模式会隐藏系统装饰)。 - 应用内容部分
通过 setContentView() 设置的布局会被添加到 android.R.id.content 这个子 FrameLayout 中。
总结
DecorView 是 Android 窗口系统的核心组件,作为连接系统 UI 和应用内容的桥梁。理解它的结构和功能有助于处理全屏、键盘交互、窗口属性等高级场景。实际开发中,通常只需通过 setContentView() 操作内容部分,而无需直接操作 DecorView。
Activity创建流程
Activity中AMS创建的。
- window的初始化是在 Acticity 创建的时候初始化, 在Acticity对象创建后,会调用attach方法,Windows对象就是这个时候创建的。
- Activity的setContentView其实调用的是PhoneWindow的setContentView。
- setContentView中调用installDecor()进行DecorView的初始化。
- onResume中会调用WindowMangerImpl的addView, ViewRootImpl就是在这个addView中创建的。
- addView会调用ViewRootImpl的setView,setView调用WMS的addView并调用requestLayout。
- requestLayout调用scheduleTraversals(会创建surface),scheduleTraversals调用见下段invalidate流程后段会有讲到主要是调用measure,layout,draw。
如下图为addView流程
View invalidate调用流程
- 起始调用
当我们希望重绘某个View时,直接调用其invalidate方法 。比如在自定义View的事件处理方法(如onClick) 或者数据更新逻辑中调用。invalidate方法会转而调用invalidate(true) ,这里的参数表示是否同时使绘图缓存无效,一般全量刷新时为true。 - invalidateInternal方法
invalidate(true)会调用invalidateInternal方法,此方法会进行以下操作:
判断是否需要重绘:调用skipInvalidate方法判断该View是否不需要重绘,不需要重绘的条件是该View不可见并且未进行动画。
- 处理重绘标志位:进一步判断View是否需要绘制,如判断表达式(mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ,若满足重绘条件,则处理相关标志位,将当前View标记为 “脏” ,即设置mPrivateFlags中的相关标志,表明该View需要重绘。
- 确定重绘区域:对于开启硬件加速的应用程序,调用父视图的invalidateChild函数绘制整个区域;否则只绘制指定的dirty区域(r变量所指区域)。这是一个向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新Rect做交集。
- ViewGroup中的调用
- invalidateChild方法:在ViewGroup中,invalidateChild方法会从当前的布局View向上不断遍历其父布局。它会先处理子View重绘相关逻辑,比如根据子View情况设置一些标志位,然后调用父布局的invalidateChildInParent方法。
- invalidateChildInParent方法:该方法会计算需要重绘的区域 ,涉及到location数组(表示自身左边、上边距离父组件的距离,确立在坐标系的相对位置 )和dirty矩形(包含自身宽高,确立需要重绘的面积大小 )。计算后会继续向上请求父布局重绘,直到父布局为ViewRootImpl 。
- ViewRootImpl中的处理
- invalidateChildInParent方法:ViewRootImpl中的invalidateChildInParent方法会检查线程是否正确 ,若dirty为null,表示要重绘整个区域,直接调用invalidate;若dirty为空且没有动画,就不需要重绘,直接返回。否则会对重绘区域进行进一步处理,如根据滚动偏移等情况调整区域。
- invalidate方法:调用invalidate方法后,会通过scheduleTraversals方法安排一次视图遍历。
- 视图遍历与绘制
- scheduleTraversals方法:安排视图遍历工作,将任务添加到消息队列,待合适时机(比如下一次绘制周期 )执行。
- performTraversals方法:视图遍历的核心方法,依次执行测量(performMeasure ,调用measure ,最终到onMeasure )、布局(performLayout ,调用layout ,最终到onLayout )、绘制(performDraw ,调用draw ,最终到onDraw )等步骤 ,完成整个View树的更新绘制 。其中performDraw会进一步调用drawSoftware ,最终触发View的draw方法,开始实际绘制。
Android Framework学习一:系统框架、启动过程
Android Framework学习二:Activity创建及View绘制流程
作者:帅得不敢出门