【Android】WMS(三)Window的更新&UI刷新

Window的更新

【Android】WMS(三)Window的更新&UI刷新_第1张图片

在 Android 中,窗口的更新是一个非常常见的事情。比如,在使用 App 过程中,需要弹出键盘窗口或者切换横竖屏时,就会发生窗口的更新。

首先,当需要更新窗口时,会调用 WindowManagerupdateViewLayout() 方法来设置参数,并将参数设置到对应的 View 上。WindowManager 的实现类为 WindowManagerImpl,但它实际上并没有做太多的工作,而是直接委托给了 WindowManagerGlobal(WMGlobal)

接下来,在 updateViewLayout() 方法中,使用来同步更新,然后通过传入的 view 参数找到其在 DecorView 中的索引值,再根据索引值找到对应的 ViewRootImpl 对象。

由于所有的窗口都是由 ViewRootImpl 来管理的,因此我们需要调用 ViewRootImpl 的 setLayoutParams() 方法,来将新的布局参数设置到对应的 ViewRootImpl 上。在这个过程中,旧的布局参数会被移除,新的布局参数会被添加进去。

UI刷新

【Android】WMS(三)Window的更新&UI刷新_第2张图片

帧率

在移动设备上,为了确保操作界面的流畅性和用户体验,帧率(FPS)是非常重要的一个因素。帧率表示在一秒钟内刷新的图像帧数,表示界面绘制的速度,而较高的帧率则意味着更加流畅的操作体验。

在 Android 系统中,默认帧率为 60 FPS,在每 16 毫秒的时间内绘制一次界面。为了保证界面的流畅性,系统会通过 VSYNC 信号来同步帧率和屏幕刷新,从而保证在一个 VSYNC 周期内最多只绘制一帧,避免了过度绘制和渲染导致 CPU 和 GPU 的过度占用,优化了系统性能和电池寿命。因此,我们可以使用一些调试工具来监测帧率和绘制时间,以便了解系统的性能并进行优化。

请求刷新

在 Android 中,UI 的刷新并不是由应用程序自行决定的。相反,它需要向同步信号服务申请同步信号以进行刷新操作。应用程序在进行 UI 绘制之前必须先向系统申请同步信号,在得到系统同意后,才能开始实际的视图重绘。

在请求刷新时,应用程序会向系统注册一个回调函数,以便在同步信号到达时可以接收通知。当系统接收到请求时,它会分配一个时间片来准备重绘操作,并在准备完成后向应用程序发送同步信号。此时,应用程序的回调函数就会被调用,以便进行实际的重绘操作。

通过这种方式,Android 系统可以保证应用程序的刷新操作在正确的时机进行,并且不会占用过多的系统资源。同时,它还能够优化系统性能和电池寿命,提高用户体验。

UI的View刷新流程

View的内容变化会调用invalidate()方法,该方法会设置 ViewRootImpl 中的 mDirty 参数,表示需要重绘的区域。

紧接着在调用 invalidate() 方法后,ViewRootImpl 会执行 scheduleTraversals() 方法准备进行绘制操作。在此期间,ViewRootImpl 同时请求VSYNC信号。此请求的目的是为了在下一次刷新屏幕的同时绘制 View 并保证画面的流畅度。

调用 scheduleTraversals() 方法后,会将一个 mTraversalRunnable 对象加入 Choreographer.CALLBACK_TRAVERSAL 的队列中等待 VSYNC 信号到来。

在 VSYNC 信号到来后,Choreographer 会执行 mTraversalRunnable 中的 run() 方法,接着执行 doTraversal() 方法,进而调用 performTraversals() 方法。

在 performTraversals() 方法中,首先对输入的触摸事件进行处理,接着开始调用 View 的 measure()layout() draw() 方法,依次完成测量、布局和绘制的过程。

在绘制出来之后,ViewRootImpl 会通过Surface或者SurfaceView将界面显示到屏幕上。

UI绘制流程

【Android】WMS(三)Window的更新&UI刷新_第3张图片

UI局部刷新

UI局部刷新(Partial UI Refresh)指的是只对某些View进行重绘刷新,而不需要对整个屏幕进行重新绘制。实际上,在 Android 中实现 UI 局部刷新是非常重要且常见的需求,在某些情况下,仅针对一个或几个 View 进行重绘能够提升应用程序的性能和响应速度。

在 Android 中,实现 UI 局部刷新主要有两种方式:

invalidate(Rect dirty) 方法:该方法可以指定需要刷新的矩形区域,从而只会对该区域内的 View 进行重绘刷新。这种方式适用于实现需求简单的 UI 局部刷新,但是需要手动计算出需要刷新的矩形区域。

ViewOverlay:ViewOverlay 是一种可以叠加在 View 上方显示的视图,它的作用是为某个具体的 View 添加覆盖层。通过使用 ViewOverlay,我们可以在不影响原有 View 布局的情况下,动态添加、删除遮盖层,并且只需对遮盖层进行重绘刷新。这种方式可以实现比较复杂的 UI 局部刷新需求。

需要注意的是,对于使用了硬件加速的 View,使用 invalidate() 方法进行局部刷新时,可能会因为硬件加速的缓存机制导致 invalidate() 方法不会生效。此时,可以使用 setLayerType(View.LAYER_TYPE_SOFTWARE, null) 方法关闭硬件加速,或者使用 View.setClipChildren(false) 方法将 View 的父容器取消裁剪,从而避免这个问题。

你可能感兴趣的:(Framework学习笔记,Android学习笔记,android,ui)