Beyond Android Views - Window,Surface,Special Views,and More

4,829 views

Published on

Introduce Android Graphics System

Published in: Technology, Business
  • Be the first to comment

Beyond Android Views - Window,Surface,Special Views,and More

  1. 1. Beyond Android Views - Window, Surface, Special Views and More Roger [email_address] [email_address] www.twitter.com/roger2yi + 易旭昕 in Google+
  2. 2. <ul><li>介绍隐藏在用户界面后面的系统底层模块 - Window , Surface , Canvas ,和它们之间的关系与交互 </li></ul><ul><li>介绍一些特殊 View 的运作原理 - SurfaceView , GLSurfaceView , TextureView </li></ul><ul><li>介绍硬件加速绘图与非硬件加速绘图的差异 </li></ul>Major Contents
  3. 3. Activity and Views
  4. 4. View <ul><li>This class represents the basic building block for user interface components. </li></ul><ul><li>A View occupies a rectangular area on the screen and is responsible for drawing and event handling. </li></ul><ul><li>View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). </li></ul>
  5. 5. Activity <ul><li>提供了一个与用户进行交互的 GUI 上下文环境(场景)和这个上下文环境的生命周期管理 </li></ul><ul><li>应用在 Activity.onCreate 中构建用户界面,调用 Activity.setContentView 方法设置界面 </li></ul>
  6. 6. Those things behind Activity and Views
  7. 7. System Services <ul><li>Activity Management Service </li></ul><ul><li>Window Management Service </li></ul><ul><li>Suface Flinger </li></ul><ul><li>etc... </li></ul>
  8. 8. The Startup of an Activity in New Process <ul><li>AMS 接收到请求要在新的进程启动一个 Activity </li></ul><ul><li>AMS 转发请求给 zygote 进程, zygote fork 一个新的进程,然后调用 ActivityThread.main 方法, ActivityThread 创建 MessageQueue , attach 到 AMS ,然后进入消息循环,这个线程就是主线程,也是所谓的 UI 线程 </li></ul><ul><li>当 ActivityThread attch 到 AMS 后, AMS 发送请求给 ActivityThread 要求启动 Activity ( LAUNCH_ACTIVITY ) </li></ul><ul><li>ActivityThread 在消息循环中启动 Activity ( handleLaunchActivity ) </li></ul><ul><ul><li>创建 Activity 后调用 onCreate ( performLaunchActivity ) </li></ul></ul><ul><ul><li>应用则在 onCreate 中设置 Content View ,然后开始跟用户的交互 ... ... </li></ul></ul>
  9. 10. Window <ul><li>Android 中的 Window 是一个十分容易混淆的概念 </li></ul><ul><li>它存在应用层面窗口和系统层面窗口的区别 </li></ul><ul><li>在系统窗口这个层面中存在客户端窗口和服务端窗口的区别 </li></ul>
  10. 11. android.view.Window <ul><li>Abstract base class for a top-level window look and behavior policy. </li></ul><ul><li>It provides standard UI policies such as a background, title area, default key processing, etc. </li></ul><ul><li>它是通常意义上我们理解的应用层面窗口, TopLevelWindow or WindowPolicy 可能是一个更合适的名字 </li></ul>
  11. 12. PhoneWindow <ul><li>PhoneWindow 是抽象类 Window 的唯一实现 </li></ul><ul><li>ActivityThread 在启动一个 Activity 的时候, Activity 会创建一个 PhoneWindow </li></ul><ul><ul><li>ActivityThread.handleLaunchActivity </li></ul></ul><ul><ul><li>-> ActivityThread.performLaunchActivity </li></ul></ul><ul><ul><li>-> Activity.attach </li></ul></ul><ul><li>Activity.setContentView 实际上是调用 PhoneWindow.setContentView ,在该方法的第一次调用时, PhoneWindow 会创建一个 DecorView 作为 Top-Level-Window 的 View Hierachy 的根节点 </li></ul>
  12. 13. View Hierachy
  13. 15. WindowManager <ul><li>android.view.WindowManager </li></ul><ul><ul><li>The interface that apps use to talk to the window manager. </li></ul></ul><ul><ul><li>真正的实现是 WindowManagerImpl ,由 PhoneWindow 在 Activity 启动时创建 </li></ul></ul><ul><ul><ul><li>ActivityThread.handleLaunchActivity </li></ul></ul></ul><ul><ul><ul><li>-> ActivityThread.performLaunchActivity </li></ul></ul></ul><ul><ul><ul><li>-> Activity.attach </li></ul></ul></ul><ul><ul><ul><li>-> PhoneWindow.setWindowManager </li></ul></ul></ul><ul><ul><li>当 Activity 启动后, ActivityThread 将 DocorView 添加到 WindowManagerImpl 中 </li></ul></ul><ul><ul><ul><li>ActivityThread.handleLaunchActivity </li></ul></ul></ul><ul><ul><ul><li>-> ActivityThread.handleResumeActivity </li></ul></ul></ul><ul><ul><ul><li>-> WindowManager.addView </li></ul></ul></ul>
  14. 16. Cont. <ul><li>WindowManagerImpl 负责跟 WMS 通讯 </li></ul><ul><ul><li>但实际上每一个 Window 跟 WMS 之间的通讯是由 ViewRootImpl 负责, ViewRootImpl 在 addView 时被创建 </li></ul></ul><ul><ul><li>这里的 Window 是指系统层面的 Window ,除了之前的 PhoneWindow 外,其它如 Dialog , Menu 都拥有一个独立的 Window </li></ul></ul><ul><ul><li>ViewRootImpl 的每一个实例都跟通过 addView 传进来一个 View Hierachy 的根节点形成一一对应的关系,它是真正意义上的 View Hierachy 的根节点 </li></ul></ul><ul><ul><li>ViewRootImpl 可以看作是系统层面的 Window 在客户端的代理者 </li></ul></ul>
  15. 17. ViewRootImpl <ul><li>The top of a view hierarchy, implementing the needed protocol between View and the WindowManager </li></ul><ul><li>This is for the most part an internal implementation detail WindowManagerImpl </li></ul>
  16. 18. Cont. <ul><li>ViewRootImpl 会打开一个 IWindowSession 用于跟 WMS 对话 </li></ul><ul><li>并通过 IWindowSession 向 WMS 注册一个窗口(实际上是让 WMS 在服务端创建一个窗口( WindowState ),并且把该服务端的窗口跟 ViewRootImpl 传过来的 IWindow 回调接口绑定在一起) </li></ul><ul><ul><li>ActivityThread.handleLaunchActivity </li></ul></ul><ul><ul><li>-> ActivityThread.handleResumeActivity </li></ul></ul><ul><ul><li>-> WindowManagerImpl.addView </li></ul></ul><ul><ul><li>-> ViewRootImpl.setView </li></ul></ul>
  17. 19. Cont. <ul><li>IWindow </li></ul><ul><ul><li>API back to a client window that the Window Manager uses to inform it of interesting things happening. </li></ul></ul><ul><ul><li>回调接口用于接收 WMS 关于窗口的消息 —— 显示 / 隐藏,大小改变,焦点变化等等 </li></ul></ul><ul><li>除了注册窗口外, ViewRootImpl 还向 WMS (通过 InputQueue )注册了一个 InputHandler 用于接收输入事件 </li></ul><ul><li>接收到的输入事件会先放在 UI 线程的消息循环中,然后通过 ViewRootImpl 进行分派,在它对应的 View Hierachy 上路由 </li></ul>
  18. 22. Overall Flow <ul><li>ActivityThead 创建 Activity </li></ul><ul><li>Activity 创建 PhoneWindow </li></ul><ul><li>PhoneWindow 创建 DecorView 作为 View Hierachy 的根节点, Client 端设置的 Content View 会 attach 到 DecorView 下面(间接) </li></ul><ul><li>PhoneWindow 创建 WindowManagerImpl </li></ul><ul><li>ActivityThead 把 DecorView 加到 WindowManagerImpl 里面 </li></ul><ul><li>WindowManagerImpl 创建 ViewRootImpl ,并把 DecorView 传给它 </li></ul><ul><li>ViewRootImpl 打开一个 Window Session 跟 WMS 通讯,通过 Session 注册一个窗口,最后客户端拥有一个 IWindow 回调接口,服务端拥有一个 WindowState 跟该回调接口绑定 </li></ul>
  19. 23. View Hierachy Rendering <ul><li>当 ViewRootImpl 建立跟 WMS 的联系,注册了窗口后,会发出第一次渲染 View Hierachy 的请求 </li></ul><ul><ul><li>ViewRootImpl.setView </li></ul></ul><ul><ul><li>ViewRootImpl.requestLayout </li></ul></ul><ul><ul><li>ViewRootImpl.scheduleTraversals </li></ul></ul><ul><li>在第一次的 View Hierachy 的渲染中( ViewRootImpl.performTraversals ), ViewRootImpl 需要创建 Surface </li></ul>
  20. 24. Cont. <ul><li>当 Surface 创建后,后续的渲染就可以通过获得 Surface 的 Canvas ( Surface.lockCanvas ) </li></ul><ul><li>然后遍历 View Hierachy ,把需要绘制的 Views 通过 Canvas 绘制到 Surface 上面( View.onDraw ) </li></ul><ul><li>绘制完后需要解锁( Surface.unlockCanvasPost ),让 SurfaceFlinger 可以将 Surface 绘制到屏幕上( Screen Composite ) </li></ul>
  21. 26. Surface <ul><li>Handle onto a raw buffer that is being managed by the screen compositor. </li></ul><ul><li>每个 Window 都有一个 Surface ,由窗口在客户端的代理者 ViewRootImpl 所拥有 </li></ul><ul><li>Surface 在 ViewRootImpl 第一次渲染 View Hierachy 时创建 </li></ul><ul><ul><li>ViewRootImpl.performTraversals </li></ul></ul><ul><ul><li>ViewRootImpl.relayoutWindow </li></ul></ul><ul><ul><li>IWindowSession.relayout </li></ul></ul>
  22. 27. Cont. <ul><li>ViewRootImpl 预先创建一个空的 Surface 对象( Java ),在需要创建真正的 Surface 的时候,它调用 IWindowSession.relayout ,这是一个 RPC ,最终是 WMS 的 relayoutWindow 被调用 </li></ul><ul><li>WMS 调用 WindowState.createSurfaceLocked 创建了一个 Surface 对象( Java ),并把这个对象的数据传回给客户端,而客户端则负责用这些数据填充预先创建的空 Surface 对象( Java ) </li></ul><ul><ul><li>实际上 WMS 是请求 SurfaceFlinger 创建真正的 Surface ,然后把 Surface 相关的信息再传回给客户端 </li></ul></ul><ul><ul><li>客户端利用这些信息来创建一个 native Surface 对象,然后把它跟 Java Surface 对象绑定在一起 </li></ul></ul><ul><ul><li>客户端的 Java Surface 对象以后就可以通过这个 native Surface 对象来操作图像缓存( GraphicsBuffer ),图像缓存可以看作是一块共享内存,在客户端和 SurfaceFlinger 之间共享 </li></ul></ul>
  23. 28. Surface & Canvas <ul><li>Surface ( Java )包含一个 Canvas ( Java ),而 Canvas ( Java )包含一个 native 的 SkCanvas 对象 </li></ul><ul><li>当调用 Surface.lockCanvas 时 </li></ul><ul><ul><li>从图像缓存队列中取出一个可用的缓存 </li></ul></ul><ul><ul><li>把当前的 Posted Buffer 的内容拷贝到新缓存中(除了 Dirty Region 之外的区域),然后将这块缓存加锁,并设置为 Locked Buffer </li></ul></ul><ul><ul><li>获得新缓存的内存地址,根据内存地址构建一个 SkBitmap </li></ul></ul><ul><ul><li>把该 SkBitmap 设置到 SkCanvas 里面 </li></ul></ul><ul><ul><li>返回跟 SkCanvas 对应的 Canvas ( Java ),透过 Canvas ( Java )绘制的内容实际上就是绘制到当前的缓存 </li></ul></ul>
  24. 29. Cont. <ul><li>当调用 Surface.unlockCanvasAndPost 的时候 </li></ul><ul><ul><li>置空 SkCanvas ,设置一个空的 SkBitmap </li></ul></ul><ul><ul><li>将 Locked Buffer 解锁并返回到图像缓存队列里面 </li></ul></ul><ul><ul><li>将 Posted Buffer 设置为 Locked Buffer ,旧的 Posted Buffer 就可以被下次取出来使用,设置 Locked Buffer 为空 </li></ul></ul><ul><ul><li>当 SurfaceFlinger 下次进行 Screen Composite 的时候就会把当前的 Posted Buffer 绘制到屏幕上 </li></ul></ul>
  25. 30. SurfaceFlinger <ul><li>应用跟 SF 之间的关系是就像是生产者与消费者的关系 </li></ul><ul><li>应用从 Surface 的 GraphicsBuffer 队列的前端取出一个缓存,然后进行绘制 </li></ul><ul><li>绘制完毕后把该缓存放置回队列的后端(生产) </li></ul><ul><li>而 SF 则不断地将 Surface 的 GraphicsBuffer 队列的最后一个缓存绘制到屏幕上(消费) </li></ul><ul><li>两者在不同的进程,是异步进行的,对队列的访问需要进行同步 </li></ul>
  26. 32. Overall Flow <ul><li>ViewRootImpl 第一次渲染 View Hierachy 的时候会创建一个 Surface </li></ul><ul><li>客户端请求 WMS 创建 Surface ,并返回 Surface 相关的数据用于构建一个 native 的 Surface 对象,并把它跟 ViewRootImpl 的 Surface ( Java )绑定在一起 </li></ul><ul><li>ViewRootImpl 在渲染时先从 Surface 获得 Canvas </li></ul><ul><li>然后把需要绘制的 Views 通过 Canvas 绘制到 Surface 上面 </li></ul><ul><li>绘制完毕后解锁该 Surface </li></ul><ul><li>SurfaceFlinger 在做 Screen Composite 的时候把解锁后的 Surface 绘制到屏幕上 </li></ul>
  27. 33. Those special Views
  28. 34. SurfaceView <ul><li>Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen </li></ul><ul><li>The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. </li></ul>
  29. 35. Cont. <ul><li>Pros </li></ul><ul><ul><li>可以跟 View Hierachy 较好地结合在一起,可以移动,改变大小,在上方叠加其它的 View </li></ul></ul><ul><ul><li>在单独的渲染线程进行渲染,渲染效率高 </li></ul></ul><ul><ul><li>SV 的 Surface 和 Window Surface 之间的混合是由系统( SurfaceFlinger )使用硬件加速完成,效率高,并且不占用应用本身的 UI 线程时间 </li></ul></ul><ul><li>Cons </li></ul><ul><ul><li>SurfaceView 的渲染毕竟跟真正的 View 不一样,它不是由 ViewRootImpl 渲染到当前的 Window Surface 上面 </li></ul></ul><ul><ul><li>不能改变 Alpha ,不支持跟下方的 View 进行 Alpha 混合 </li></ul></ul><ul><ul><li>不能做 Rotation , Skew 等变换 </li></ul></ul>
  30. 36. GLSurfaceView <ul><li>An implementation of SurfaceView that uses the dedicated surface for displaying OpenGL rendering. </li></ul><ul><li>A GLSurfaceView provides the following features: </li></ul><ul><ul><li>Manages a surface, which is a special piece of memory that can be composited into the Android view system. </li></ul></ul><ul><ul><li>Manages an EGL display, which enables OpenGL to render into a surface. </li></ul></ul><ul><ul><li>Accepts a user-provided Renderer object that does the actual rendering. </li></ul></ul><ul><ul><li>Renders on a dedicated thread to decouple rendering performance from the UI thread. </li></ul></ul><ul><ul><li>Supports both on-demand and continuous rendering. </li></ul></ul><ul><ul><li>Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls. </li></ul></ul>
  31. 37. Cont. <ul><li>GLSurfaceView 创建一个内部的线程 GLThread </li></ul><ul><li>在该线程运行环境下创建一个 EglContext </li></ul><ul><li>创建一个 EglSurface ( Window Surface ) </li></ul><ul><li>设置之前创建的 EglContext 为当前的 GL Context 并绑定到创建的 EglSurface 上 </li></ul><ul><li>在该线程内就可以通过 EGL 指令在当前的 GL Context 上绘图 </li></ul>
  32. 38. Cont. <ul><li>GLSurfaceView 支持两种不同的绘图模式 </li></ul><ul><ul><li>连续模式下, GLThread 会不断调用 Renderer.onDrawFrame 进行绘图 </li></ul></ul><ul><ul><li>Dirty 模式下, GLThread 处于等待状态,直到程序发送绘图请求( GLSurfaceView.requestRender )才调用 Renderer.onDrawFrame 进行绘图,绘制完一帧后重新进入等待状态 </li></ul></ul><ul><li>在 Renderer.onDrawFrame 的回调中,应用可以通过 SDK 提供的 EGL API 绘图,也可以转到 native 端,使用 NDK 提供的 EGL API 绘图 </li></ul>
  33. 40. TextureView <ul><li>Since Android 4.0 ,只在硬件加速环境下起作用 </li></ul><ul><li>具备 SurfaceView 的特性 </li></ul><ul><ul><li>但是可以跟其它普通的 View 一样实现 Rotation , Screw 等变换 </li></ul></ul><ul><ul><li>支持 Alpha ,可以跟它下方的 View 进行 Alpha 混合 </li></ul></ul><ul><li>可以基于 TextureView 创建一个 GL Surface ,在上面进行 OpenGL 渲染 </li></ul>
  34. 41. Things become more complicated after Android 3.0 ...
  35. 42. HW Accelerated 2D Rendering <ul><li>Android 3.0 后开始支持硬件加速的 2D 绘图,原有的绘图流程变得更加复杂 </li></ul><ul><li>所谓硬件加速的 2D 绘图,就是将 2D Graphics API 的实现改成使用 OpenGL API 来进行绘图 </li></ul><ul><li>OpenGL 的绘图模式跟一般的 2D 绘图有很大区别,它需要先将绘图所需的各种素材如贴图,多边形顶点阵列, Shader 等先加载到当前的 GLContext ,然后流水线式的顺序执行绘图指令,通过这种方式来充分利用硬件的能力 </li></ul>
  36. 43. ViewRootImpl <ul><li>当 Actitity 的 View Hierachy 的根节点被添加到 WindowManager 的时候( WindowManager.addView ), WindowManager 的实现类 WindowManagerImpl 会创建一个 ViewRootImpl 并把它跟传进来的 View 绑定在一起( ViewRootImpl.setView ),并且 ViewRootImpl 会根据是否开启硬件加速来决定是否创建一个 HardwareRenderer </li></ul><ul><li>在 ViewRootImpl 第一次渲染 View Hierachy 时,会创建 Surface ,如果开启硬件加速,则通过 HardwareRenderer 在当前的 UI 线程初始化 EGL 绘图环境(类似 GLSurfaceView ) </li></ul>
  37. 44. Cont. <ul><li>在 ViewRootImpl 真正渲染 View Hierachy 时,如果开启硬件加速,则从 HardwareRenderer 获得一个 HardwareCanvas ,然后 View Hierachy 的渲染通过 HardwareCanvas 来进行 </li></ul><ul><li>HardwareCanvas 跟一个 native 的 OpenGLRenderer 绑定,通过它调用 EGL API 来完成真正的绘制 </li></ul>
  38. 45. DisplayList and Hardware Layer <ul><li>为了充分利用硬件加速的能力, Android 3.0 还引入了 DisplayList 和 Hardware Layer </li></ul><ul><li>DisplayList 用于记录一系列 OpenGL 绘图指令和缓存所需的各种绘图素材( Bitmap , Paint , Shape , Shader ),当 View 的内容不发生变化时,可以直接使用 DisplayList 进行绘制而不需要重新调用 onDraw </li></ul><ul><li>Hardware Layer 用于缓存绘制的内存到 Frame Buffer Object ,当内容不发生变化时,可以直接使用 Layer 进行 Layer Composite 获得更快的绘图速度 </li></ul>
  39. 47. Reference <ul><li>Android 圖形系統 -- 設計與實做分析 </li></ul><ul><li>How to replace GLSurfaceView with TextureView in Android Ice Cream Sandwich? </li></ul>
  40. 48. The End Thank you for your listening Yours Sincerely, Roger

×