Android窗口管理分析(1):View如何绘制到屏幕上的主观理解

简介: Android窗口管理分析(1):View如何绘制到屏幕上的主观理解

窗口管理可以说是Android系统中最复杂的一部分,主要是它涉及的模块比较多,虽然笼统的说是窗口管理,其实,除了WindowManagerService还包括SurfaceFlinger服务、Linux的共享内存及tmpfs文件系统、Binder通信、InputManagerService、动画、VSYNC同步技术等,一篇文章不可能分析完全,但是可以首先对于窗口的显示与管理有一个大概的轮廓,再分块分解,涉及的知识点大概如下:


image.png


WMS的作用是窗口管理 不负责View绘制


既然是概述,我们不妨直观的思考一个问题,Activity是如何呈现到屏幕上的,或者说View是如何被绘制到屏幕上来的?或多或少,开发者都知道WindowManagerService是负责Android的窗口管理,但是它其实只负责管理,比如窗口的添加、移除、调整顺序等,至于图像的绘制与合成之类的都不是WMS管理的范畴,WMS更像在更高的层面对于Android窗口的一个抽象,真正完成图像绘制的是APP端,而完成图层合成的是SurfaceFlinger服务。这里通过一个简单的悬浮窗口来探索一下大概流程:

    TextView mview=new TextView(context);
    ...<!--设置颜色 样式-->
    WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
    wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
    wmParams.format = PixelFormat.RGBA_8888;
    wmParams.width = 800;
    wmParams.height = 800;
    mWindowManager.addView(mview, wmParams);

以上代码可以在主屏幕上添加一个TextView并展示,并且这个TextView独占一个窗口。在利用WindowManager.addView添加窗口之前,TextView的onDraw不会被调用,也就说View必须被添加到窗口中,才会被绘制,或者可以这样理解,只有申请了依附窗口,View才会有可以绘制的目标内存。当APP通过WindowManagerService的代理向其添加窗口的时候,WindowManagerService除了自己进行登记整理,还需要向SurfaceFlinger服务申请一块Surface画布,其实主要是画布背后所对应的一块内存,只有这一块内存申请成功之后,APP端才有绘图的目标,并且这块内存是APP端同SurfaceFlinger服务端共享的,这就省去了绘图资源的拷贝,示意图如下:


image.png

以上是抽象的图层对应关系,可以看到,APP端是可以通过unLockCanvasAndPost直接同SurfaceFlinger通信进行重绘的,就是说图形的绘制同WMS没有关系,WMS只是负责窗口的管理,并不负责窗口的绘制,这一点其实也可以从IWindowSession的binder通信接口看出来:

interface IWindowSession {
    int add(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            in int viewVisibility, out Rect outContentInsets,
            out InputChannel outInputChannel);
    int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            in int viewVisibility, in int layerStackId, out Rect outContentInsets,
            out InputChannel outInputChannel);
    int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility,
            int flags, out Rect outFrame, out Rect outOverscanInsets,
            out Rect outContentInsets, out Rect outVisibleInsets,
            out Configuration outConfig, out Surface outSurface);
    void remove(IWindow window);
...
}

从参数就可以看出,APP与WindowManagerService通信的时候没有任何View相关的信息,更不会说将视图的数据传递给WMS,基本都是以IWindow为基本单位进行通信的,所以涉及的操作也都是针对窗口的,比如整个窗口的添加、移除、大小调整、分组等,单单从窗口显示来看,WMS的作用确实很明确,就是在服务端登记当前存活窗口,后面还会看到,这会影响SurfaceFlinger的图层混合,可以说是为SurfaceFlinger服务的。


在对于日常开发来说,WMS的窗口分组有时候会对开发带来影响,如果不知道窗口分组管理,可能有点忙迷惑,比如Dialog必须使用Activity的Context,PopupWindow不能作为父窗口,尤其要避免作为Webview的容器等,这些都跟WMS窗口的组织有关系。


PopupWindow、Dialog、Activity三者都有窗口的概念,但又各有不同,Activity属于应用窗口、PopupWindow属于子窗口,而Dialog位于两者之间,从性质上说属于应用窗口,但是从直观理解上,比较像子窗口(其实不是)。Android中的窗口主要分为三种:系统窗口、应用窗口、子窗口,Toast就属于系统窗口,而Dialog、Activity属于应用窗口,不过Dialog必须依附Activity才能存在。PopupWindow算是子窗口,必须依附到其他窗口,依附的窗口可以使应用窗口也可以是系统窗口,但是不能是子窗口。

image.png

当然,WMS的作用不仅只是管理窗口,它还负责窗口动画、Touch事件等,后面会逐个模块分析。


View绘制与数据传递


既然WMS的作用只是窗口管理,那么图形是怎么绘制的呢?并且这些绘制信息是如何传递给SurfaceFlinger服务的呢?每个View都有自己的onDraw回调,开发者可以在onDraw里绘制自己想要绘制的图像,很明显View的绘制是在APP端,直观上理解,View的绘制也不会交给服务端,不然也太不独立了,可是View绘制的内存是什么时候分配的呢?是谁分配的呢?我们知道每个Activity可以看做是一个图层,其对应一块绘图表面其实就是Surface,Surface绘图表面对应的内存其实是由SurfaceFlinger申请的,并且,内存是APP与SurfaceFlinger间进程共享的。实现机制是基于Linux的共享内存,其实就是MAP+tmpfs文件系统,你可以理解成SF为APP申请一块内存,然后通过binder将这块内存相关的信息传递APP端,APP端往这块内存中绘制内容,绘制完毕,通知SF图层混排,之后,SF再将数据渲染到屏幕。其实这样做也很合理,因为图像内存比较大,普通的binder与socket都无法满足需求,内存共享的示意图如下:

image.png


总结


其实整个Android窗口管理简化的话可以分为以下三部分


  • WindowManagerService:WMS控制着Surface画布的添加与次序,动画还有触摸事件
  • SurfaceFlinger:SF负责图层的混合,并且将结果传输给硬件显示
  • APP端:每个APP负责相应图层的绘制,
  • APP与SurfaceFlinger通信:APP与SF图层之间数据的共享是通过匿名内存来实现的。


目录
相关文章
|
7月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
532 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
7月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
130 0
|
7月前
|
Android开发 开发者
Android自定义view之利用drawArc方法实现动态效果
本文介绍了如何通过Android自定义View实现动态效果,重点使用`drawArc`方法完成圆弧动画。首先通过`onSizeChanged`进行测量,初始化画笔属性,设置圆弧相关参数。核心思路是不断改变圆弧扫过角度`sweepAngle`,并调用`invalidate()`刷新View以实现动态旋转效果。最后附上完整代码与效果图,帮助开发者快速理解并实践这一动画实现方式。
187 0
|
7月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
131 0
|
7月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
341 65
Android自定义view之网易云推荐歌单界面
|
7月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
686 84
|
4月前
|
机器学习/深度学习 Android开发 数据安全/隐私保护
手机脚本录制器, 脚本录制器安卓,识图识色屏幕点击器【autojs】
完整的UI界面,包含录制控制按钮和状态显示 屏幕点击动作录制功能,记录点击坐标和时间间隔
|
7月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
204 3
|
7月前
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
136 0
Android自定义view之围棋动画(化繁为简)
|
7月前
|
Java Android开发 开发者
Android自定义view之围棋动画
本文详细介绍了在Android中自定义View实现围棋动画的过程。从测量宽高、绘制棋盘背景,到创建固定棋子及动态棋子,最后通过属性动画实现棋子的移动效果。文章还讲解了如何通过自定义属性调整棋子和棋盘的颜色及动画时长,并优化视觉效果,如添加渐变色让白子更明显。最终效果既可作为围棋动画展示,也可用作加载等待动画。代码完整,适合进阶开发者学习参考。
154 0

热门文章

最新文章