- 下图,在PerfDog,使用华为P30Pro,查看微博的刷新情况,静态的微博内容在不滑动的时候,刷新率就是0fps,快速滑动时,刷新率在60fps左右,还能查看CPU和内存是使用情况。
- 下图,而在微博播放视频时,刷新率一直就是60fps左右了。
-
下图,普通的APP都基本能达到60fps,相机就不是了,相机拍照稳定在30fps,而自拍时,开启美颜,降到24fps了,看来相机加AI美颜是比较吃性能的。
-
小知识,电影或者是网上看的视频一般是24帧/秒的速度播放的,即可以省性能,效果也不错,索尼A7M3相机可以录制120帧的慢动作,可以做4倍或者5倍升格。
1.3 CPU Profile
- Android性能优化 - 启动速度优化 里有讲怎么使用 Profile 看各个方法的耗时,布局的加载也是会显示的,也可以用来分析卡顿的可能情况。
2.1 过度绘制
-
Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。
-
蓝色绿色是比较好的情况,红色就是层级较多了,为了实现好看的效果,就会套多层布局,过度绘制的多了消耗性能,对与入门机就会卡顿了。
-
手机进入开发人员选项,调试GPU过度绘制,打开显示过度绘制区域。
-
贝壳APP的布局大多是蓝色绿色的,说明他们APP就没什么过度绘制的情况,非常好。
- 到下面的列表就会有过度绘制的情况,但区域不大,只有内容的部分。
- 开发人员选项,显示布局边界,可以看到贝壳的布局层级确实不多,也非常的清晰工整。
- 微博APP的过度绘制区域基本占满整个屏幕了,除了微博还有微信淘宝等列表APP也是大多数红色的,原因可能是列表类的APP,除了父布局,里面还要套RecyclerView,再套itemview,无法避免的过度绘制;但整个item都过度绘制了,贝壳就会比较好一些。
- 微博的布局看起来就会复杂一些了。
2.2 解决过度绘制
-
1.上面的微博跟贝壳比较,微博的item是有过度绘制的情况,那么我们在写RecyclerView的时候,如果RecyclerView的父布局、RecyclerView、item三者的背景只要其中一个设置就可以了,没有设置背景就不会渲染,否则就会有过度绘制的情况。
-
2.父布局套子布局也是尽量只设置其中一个背景,除非没办法都需要背景。
-
3.子view一般绘制后是会覆盖父view,所以一般选择把背景设置在子view。
-
4.视图的层级结构能减少就减少,层级越多绘制速度越慢。
-
5.尽量少设置view的透明度,如果一个view设置了alpha,那他需要知道下面的view是什么内容,再绘制自己,就是过度绘制。如果是文字有透明度,可以在色号里就设置好。
2.3 层级优化
-
Android studiol有布局层级的工具,Layout Inspector,运行起来app后,可以看到每个页面的层级结构。层级太多,肯定就会造成卡顿,启动慢,在启动优化有说,
-
左边可以看到布局树的具体内容。
-
像ScrollView里面只能放一个ViewGroup,是不可缩减的,但 LinearLayout套LinearLayout 是可以通过ConstraintLayout解决的,约束布局可以说是结合了线性布局跟相对布局的优点,能有效减少层级。
2.4 使用merge
-
我们有一些布局是可以通用的,避免重复代码,就可以使用 include。
-
但是,如果使用 include,但里面的布局又是一个 ViewGroup 的话,就会造成层级过多,这个时候就可以使用 merge 标签了,里面的子view根据会外部include地方的ViewGroup来排列,从而减少层级。
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<merge xmlns:android="schemas.android.com/apk/res/and…"
android:id="@+id/ll_head"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="text1"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="text2"
android:textSize="16sp" />
复制代码
- 可以看到使用merge 里面的 view 直接在 LinearLayout 的层级里。
2.5 ViewStub
-
我们有时根据需求,先把布局画好,然后把 android:visibility 设置成 “invisible” 或者是 “gone” ,invisible 和 gone 虽然看不见,但他们还是有初始化,占用这内存和资源,前者还占用着位置。
-
我们可以使用 ViewStub 来包裹这些需要隐藏显示的 view,它是一个轻量级的view,不可见不占用资源,只有当设置 inflate 时才初始化显示。
<ViewStub
android:id="@+id/viewStub_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout="@layout/layout_title"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout xmlns:android="schemas.android.com/apk/res/and…"
最后
考虑到文章的篇幅问题,我把这些问题和答案以及我多年面试所遇到的问题和一些面试资料做成了PDF文档,如果有需要的朋友可以私信我【面试】免费领取
喜欢的朋友可以关注、转发、点赞 感谢!