《Android高性能编程》打造布局笔记

《Android高性能编程》打造布局笔记

2018, Apr 19    

预览

目标是要保证16.667毫秒内顺利刷新,如果被绘制次数太多,占用过多CPU资源,帧会被丢弃。

视图最顶层的视图叫做DecorView,一般要避免绘制这个默认背景,方法是,主题设为Theme.NoBackground,或者 activity中添加android:windowbackground属性并设为null

屏幕撕裂:相邻的不同两帧被绘制到同一个屏幕上。原因是,绘制帧的数据源是单向的,新的一帧会覆盖上一帧,然而只有一个缓存区可读取。当屏幕要刷新时,读取的帧处于未完成状态,就是出现撕裂。解决方案:双缓冲区。

垂直同步:保证从缓冲区从后台到前台的过程中出现屏幕更新。它限制屏幕的绘制,必须等到垂直同步的信号到达后,才会输出影像信号。但是,当帧速率小于刷新率时,会出现延迟和卡顿。

硬件加速:invalidation-[storing]-redrawing. Storing过程中,只有需要被更新的视图才进行重绘(更新存储),并且在重绘之后被存储起来(离屏位图),以便使用,从而减少运行时的计算量。在redrawing阶段,用存储的绘图进行更新。(4.x以后的手机一般都支持硬件加速)。提高动画性能:在动画启动前,开启硬件加速,在结束时,立即关闭,以释放被占用的显存。每当让View执行一个Alpha动画,或者仅仅设一个Alpha值时,都可以考虑使用硬件加速。6.0以后会被自动应用。

过渡绘制:哪怕没有被显示,一样需要消耗相应的计算和内存,并且影响着性能。对背景使用9-patches可以在一定程度上减少过渡绘制,在9-patches图中,被其他视图所遮盖的部分,会被adnroid2d渲染器优化为透明。

多窗口模式:android N开始。自由动态模式,画中画模式。注意生命周期。可以通过Acitivity的以下属性进行相关配置(ResizeableAcitivity和supportsPictureInPicture)

最佳实践

布局层级管理

过程:测量->摆放。

当某个View的属性发生变化,View自身会调用invalidation方法,自底向上传播该请求,直到根布局。所以布局层级不近会影响开始的绘制,在整个界面的交互中,也会有影响。扁平化很重要。

布局复用

<include>

<merge>系统会自动忽略这个表现,直接放入布局文件中。在调用inflate时,必须为其提供父容器

<ViewStub>关联一个布局文件,但直到运行时,调用inflate或着setvisibility才会被绘制,之后会被实例化的布局替代,不再能被访问,应使用inflateid。可以通过它延迟部分view的加载,缩短首次加载时间,减少一定的内存分配。

Adapterder的视图和回收

种类: ArrayAdapter, CursorAdapter, SimpleAdapter

ViewHodler:用来解决频繁调用findviewbyid会消耗大量计算问题,它是一个静态类,用于存储布局中的view,可以再后续被重复使用。RecyclerView将viewholder的使用标准化了,它会自动通过内建的viewholder机制来实现控件的回收和复用。

自定义视图和布局

方式:包装成一个可重用对象;覆盖view.onDraw方法

注意:1. 如果再View.onMeasure方法中调用view.setMeasuredDimension方法,会抛出异常;2. 每当view的边界发生变化,或者它占据的空间发生变化而需要被再次测量时,需要调用view.requestLayout方法。3. 避免再ondraw中分配内存是很重要的

屏幕缩放

注意适配。dp

调试工具

design窗口:component tree

hierachy view: tree view; view properties, tree overview, layoutview

设备上的调试工具

systrace

在写布局文件时,有些情况下match_parent与wrap_content都可实现需求,这时可优先使用match_parent,熟悉View的measure就会知道,match_parent的实现逻辑比wrap_content要简单很多。